feat: Documentation and API reference (#348)

Co-authored-by: Vadim Smirnov <smirnou.vadzim@gmail.com>
Co-authored-by: zakariasaad <zakaria.elas@gmail.com>
Co-authored-by: Vilfred Sikker <vilfredsikker@gmail.com>
Co-authored-by: Kasper <kasper@medusa-commerce.com>
Co-authored-by: Sebastian Rindom <skrindom@gmail.com>
Co-authored-by: Kasper Fabricius Kristensen <45367945+kasperkristensen@users.noreply.github.com>
This commit is contained in:
Oliver Windall Juhl
2021-08-24 18:16:42 +02:00
committed by GitHub
parent 5d63b0c8d2
commit f76aa816a5
71 changed files with 16482 additions and 1156 deletions

View File

@@ -0,0 +1,306 @@
---
title: Create a headless ecommerce store with Gatsby, Contentful & Medusa
---
# Creating a headless ecommerce store with Gatsby, Contentful and Medusa
> Medusa is an open source headless commerce engine that allow you to create amazing digital commerce experiences. Medusa is highly customizable, allowing you to extend the core to fit your needs.
## Introduction
In this guide we will go over how to set up a modern e-commerce store using [Gatsby](https://gatsby.com) as a front end, [Contentful](https://contentful.com) as a CMS system and Medusa as a store engine. The resulting e-commerce store will be blazingly fast, highly extendable and will provide the necessary foundation to grow and evolve your e-commerce stack as your business expands to new markets and develops new software requirements.
## Overview
After following the steps outlines in this series you will have:
- A Medusa store engine capable of managing products, processing orders, handling orders and integrating with all the tools in your e-commerce stack.
- A statically generated Gatsby storefront that is on brand and customizable from homepage to checkout flow.
- A headless CMS system that can be modified and extended to create the best customer experience.
You will make use of `medusa-plugin-contentful` which is a plugin to your Medusa store engine that syncronizes products and product variants between your Medusa engine and your Contentful space. This allows you to perform content enrichment in Contentful while keeping your core master data in Medusa, for a truly headless commerce setup.
Other concepts that will be covered in this series include:
- Gatsby plugins and [File System Route API](https://www.gatsbyjs.com/docs/reference/routing/file-system-route-api/)
- [Contentful Migrations](https://www.contentful.com/developers/docs/tutorials/cli/scripting-migrations/)
- Medusa payments, fulfillments and plugins
If you want to jump straight to the code for this series you can checkout:
- [`medusa-starter-contentful`](https://github.com/medusajs/medusa-starter-contentful)
- [`medusa-contentful-storefront`](https://github.com/medusajs/medusa-contentful-storefront)
## Prerequisites
> For a full guide to how to set up your development environment for Medusa please see [the tutorial](https://docs.medusa-commerce.com/tutorials/set-up-your-development-environment)
In order to get you started with your Gatsby, Contentful, Medusa store you must complete a couple of installations:
- Install the Medusa CLI
```
yarn global add @medusajs/medusa-cli
npm install -g @medusajs/medusa-cli
```
- Install the Gatsby CLI
```
yarn global add gatsby-cli
npm install -g gatsby-cli
```
- [Create a Contentful account](https://www.contentful.com/sign-up/)
- [Install Redis](https://redis.io/topics/quickstart)
```
brew install redis
brew services start redis
```
Medusa has support for SQLite and PostgreSQL and uses Redis for caching and queueing of asynchronous tasks. Redis is required for `medusa-plugin-contentful` to work correctly.
## Setting up your Medusa server
We will make use of `medusa new` to setup your local Medusa server.
```sh
medusa new medusa-contentful-store https://github.com/medusajs/medusa-starter-contentful
```
This command will setup a new directory at `medusa-contentful-store`, clone the `medusa-starter-contentful` into that directory and install the dependencies for the project.
### What's inside
You can now do `cd medusa-contentful-store` and open up your project in your text editor. Below is an overview of the directory structure and a walkthrough of what the different files do.
```
medusa-contentful-store
├── contentful-migrations
| ├── hero.js
| ├── index.js
| ├── link.js
| ├── navigation-item.js
| ├── navigation-menu.js
| ├── page.js
| ├── product-variant.js
| ├── product.js
| ├── region.js
| ├── tile-section.js
| └── tile.js
├── data
| ├── contentful-seed.json
| └── seed.json
├── src
| ├── api
| ├── loaders
| ├── services
| └── subscribers
├── .env
├── medusa-config.js
├── package.json
└── README.md
```
#### `package.json`
If you are familiar with Node you will probably notice that your Medusa store is simply a Node project. Looking inside the `package.json` file you will find that one of the packages that is installed in the project is the `@medusajs/medusa` package. This is the core Medusa package that comes prepacked with all the functionality necessary to do digital commerce - it is also this package that makes sure to register and use the plugins and custom functionality that are configured for your store.
#### `medusa-config.js`
Your plugins and store configuration is managed in the `medusa-config.js`, if you open up the file you will see that `medusa-plugin-contentful` is configured with options as shown below. Later we will be setting up your Contentful space so that we can add the necessary environment variables to your `.env` file.
```javascript
// medusa-config.js
// Contentful Variables
const CONTENTFUL_SPACE_ID = process.env.CONTENTFUL_SPACE_ID || "";
const CONTENTFUL_ACCESS_TOKEN = process.env.CONTENTFUL_ACCESS_TOKEN || "";
const CONTENTFUL_ENV = process.env.CONTENTFUL_ENV || "";
const plugins = [
...,
{
resolve: `medusa-plugin-contentful`,
options: {
space_id: CONTENTFUL_SPACE_ID,
access_token: CONTENTFUL_ACCESS_TOKEN,
environment: CONTENTFUL_ENV,
},
},
...
];
module.exports = {
projectConfig: {
redis_url: REDIS_URL,
database_database: "./medusa-db.sql",
database_type: "sqlite",
store_cors: STORE_CORS,
admin_cors: ADMIN_CORS,
},
plugins,
};
```
#### `/src`
In the `/src` directory there are 4 special subdirectories that are added for you already. These special directories can be used to add custom functionality to your store. Custom functionality can include custom endpoints (configured in `/api`), custom business logic (configured in `/services`), pub/sub-like subscriptions for asyncrhonous integration tasks (configured in `/subscribers`) and finally loader functions to be called when your Medusa server starts up (configured in `/loaders`). If you want to learn more about how to add custom functionality you can checkout [the tutorial](https://docs.medusa-commerce.com/tutorials/adding-custom-functionality).
#### `/data`
We will be using two seed scripts to kickstart your development, namely `yarn seed:contentful` and `yarn seed`. Data for these seed scripts are contained in the `/data` directory.
When the seed scripts have been executed you will have a Contentful space that holds all the data for your website; this includes content for Pages, Navigtion Menu, etc.
#### `/contentful-migrations`
This directory contains scripts that create content types in your Contentful space. Contentful allows you to customize your content types with fields that can be used to hold all sorts of data, this makes it possible to create advanced data structures that will later be used to lay out your website. Writing migration scripts to evolve your content types is a really powerful tool as you can use it in CI/CD pipelines and makes your projects much more portable.
The migrations included in this project will create the following content types:
- **Page**: Represents a page on your website. Each page has a title and can take any number of "Content Modules". Content Modules can be either of the type Hero or Tile Section.
- **Hero**: a component that can take a Title, CTA and a background image.
- **Tile**: a component that can be added to a Tile Section and renders a Title, CTA and an Image.
- **Tile Section**: a component that can hold a number of Tiles or Products. When used with a Product, the Tile Section will display the product thumbnail and it's title and will link to the product page.
- **Link**: a component that can link to an external or internal path; or, alternatively, hold a reference to a Page or Product entry. If used with Page or Product, the link path will be infered from the referenced entry.
- **Navigation Item**: an item to include in a Navigation Menu. Each navigation item has a title that can be displayed in a menu and a link that defines where the user will be navigated to when the item is clicked.
- **Product**: represents a product as syncronized from Medusa. A product's variants will be copied over as well.
- **Product Variant**: The variants of a product.
- **Region**: Represents an available region in Medusa.
## Creating a Contentful space
To create a new Contentful space log in to your Contentful account. If you already have a Contentful account with a Space configured you can click your organization name in the top left corner to reveal an overview of your organization's spaces. At the bottom of the spaces list you should click "Add space".
**Select "Community space" and "Web app only"**
In this guide we will be using a free space which gives you an incredibly strong foundation for creating on-brand customer experiences and advances shopping flows.
![](https://i.imgur.com/JOAG8uk.png)
**Add a name and select "Empty space"**
![](https://i.imgur.com/Yt8xxoX.png)
Once your space is set up you can go to your space home. We will now get the credentials needed for `medusa-plugin-contentful` to work.
Open your `.env` file in your text editor you should see:
```shell
# .env
JWT_SECRET=something
COOKIE_SECRET=something
STRIPE_API_KEY=
STRIPE_WEBHOOK_SECRET=
CONTENTFUL_SPACE_ID=
CONTENTFUL_ACCESS_TOKEN=
CONTENTFUL_ENV=
```
Your `CONTENTFUL_SPACE_ID` can be found by going to your space home and checking your browser's URL bar. The space id is the alphanumeric string following `https://app.contentful.com/spaces/`. Copy this string and paste it into your `.env` file.
To get your `CONTENFUL_ACCESS_TOKEN` go to your space home and click **Settings** > **API keys**
![](https://i.imgur.com/ZF2VQSo.png)
Then click **Content management tokens** and click **Generate personal token**. After giving your token a name you can copy it to your `.env`
![](https://i.imgur.com/hcuAeKd.png)
For `CONTENTFUL_ENVIRONMENT` add `master`.
You should now have a `.env` that looks like this:
```shell
# .env
JWT_SECRET=something
COOKIE_SECRET=something
STRIPE_API_KEY=
STRIPE_WEBHOOK_SECRET=
CONTENTFUL_SPACE_ID=****
CONTENTFUL_ACCESS_TOKEN=CFPAT-*******
CONTENTFUL_ENV=master
```
## Migrating and Seeding your Contentful space
Now that we have collected your credentials we are ready to migrate the Contentful space to add the content types we talked about earlier. To migrate the Contentful space open up your command line and `cd` into `medusa-contentful-store`.
You can now run:
```shell
yarn migrate:contentful
```
This script will run each of the migrations in the `contentful-migrations` directory. After it has completed navigate to your Contentful space and click "Content model" in the top navigation bar. You will see that the content types will be imported into your space. Feel free to familiarize yourself with the different types by clicking them and inspecting the different fields that they hold.
![](https://i.imgur.com/E4x43vX.png)
The next step is to seed the Contentful space with some data that can be used to display your ecommerce store's pages and navigation. To seed the database open up your command line and run:
```shell
yarn seed:contentful
```
In your Contentful space navigate to "Content" and you will be able to see the different entries in your space. You can filter the entries by type to, for example, only view Pages:
![](https://i.imgur.com/5s8NNLT.png)
You will notice that there are not any Products in your store yet and this is because we haven't created any products in your Medusa store.
To do this open your command line and run:
```shell
yarn seed
yarn start
```
This will seed your Medusa database, which will result in `medusa-plugin-contentful` synchronizing data to your Contentful space. Everytime you add or update a product the data will be copied into your Contentful space for further enrichment.
## Setting Featured Products
In Contentful navigate to "Content" and find the Page called "Home". We will now add some featured products to the home page.
- Click the "Home" entry and scroll down to the field called "Content modules"
![](https://i.imgur.com/ab50vOa.png)
- Click the Content module named "Featured Products" and click "Add content" in the "Tiles" field
![](https://i.imgur.com/5GACc0e.png)
- Click "Add existing content" as e will be adding the products that were copied over by Medusa
![](https://i.imgur.com/igFPzdr.png)
- Select Medusa Waterbottle and Medusa Shirt and click "Insert 2 entries"
Make sure that everything is published by hitting publish in the sidebar on the right-hand side.
## Setting up your Gatsby storefront
Now that we have your Medusa server running and your Contentful space seeded with some starter data it is time to add a presentational layer that can be used by customers to browse and purchase the items in your store.
We have already created the storefront and you can install and use it by simply running:
```
gatsby new medusa-contentful-storefront https://github.com/medusajs/medusa-contentful-storefront
```
Once `gatsby new` is complete you should rename the `.env.template` file to `.env` and add a Content Delivery token. Your content delivery token is different from the personal access token you generated earlier, so make sure that you are using the correct token when you paste it into your `.env`.
To get your token go to **Settings** > **API Keys** > **Add API key**. Now click save and copy the token specified in the field "Content Delivery API - access token".
After you have copied the token and your space ID to your `.env`, you can run `yarn start` which will start your Gatsby development server on port 8000.
You can now go to https://localhost:8000 to check out your new Medusa store.
![](https://i.imgur.com/8MHrA73.png)
## Summary
Using three powerful tools we have now set up a modern headless ecommerce store on our local development machine. This setup can scale with your business's needs and evolve to fit create amazing commerce expereiences that are unique and on brand. The steps we took in this guide were really simple and fast: first we created a Medusa server using the Medusa CLI, we then configured a Contentful space by running migrations and seed scripts. We also installed a Gatsby front end for our Medusa store using the Gatsby CLI.
## What's next
In the next part we will dig deeper into how Contentful can be used to create pages, enrich your products and structure your content. We will also take a look at the files in your Gatsby storefront.
Stay tuned!

View File

@@ -0,0 +1,99 @@
---
title: Notifications and automated flows
---
# Notification API and how to structure email flows
### Introduction
Plugins offer a way to extend and integrate the core functionality of Medusa. For a walkthrough of the implementation details behind these, please see [Plugins in Medusa](https://docs.medusa-commerce.com/how-to/plugins).
Medusa makes it possible for plugins to implement the Notification API. The API allows for different types of implementations of notifications (emails, text messages, Slack messages, etc), that are sent as a reaction to events in Medusa. All Notifications are stored in the database with information about the receiver of the notification and what plugin was in charge of sending it. This allows merchants to resend notifications, but also gives an overview of what communication has been sent to customers.
### How it works
The Notification API works by subscribing to all events that are emitted to the Event Bus and channeling them through to notification plugins that listen to the events. In a plugin you can subscribe to a notification event by exporting a subscriber class that calls `notificationService.subscribe`:
```jsx
// src/subscribers/my-notification.js
class MyNotification {
constructor({ notificationService }) {
// Subscribe to order.placed events
notificationService.subscribe("order.placed", "my-service");
}
}
export default MyNotification;
```
The above code tells the notification service to send `order.placed` events to the `my-service` notification service implemented in your plugin.
For a plugin to work with the Notification API you must implement 2 methods `sendNotification` and `resendNotification`;
```jsx
// src/services/my-notification.js
class MyService extends NotificationService {
static identifier = "my-service";
constructor({ orderService }, options) {
super();
this.options_ = options;
this.orderService_ = orderService;
}
async sendNotification(eventName, eventData, attachmentGenerator) {
let sendData;
switch (eventName) {
case "order.placed":
sendData = await this.orderService_.retrieve(eventData.id);
break;
default:
// If the return value is undefined no notification will be stored
return;
}
await CoolEmailSender.send({
email: sendData.email,
templateData: sendData,
});
return { to: sendData.email, data: sendData };
}
async resendNotification(notification, config, attachmentGenerator) {
const recipient = config.to || notification.to;
await CoolEmailSender.send({
email: recipient,
templateData: notification.data,
});
return { to: sendOptions.to, data: notification.data };
}
}
export default MyService;
```
> **Note:** a notification service must have a static property called `identifier` this is used to determine which classes are called when subscribing to different events. In this case the service identifier is `my-service` so to subscribe to notifications you must use:
> `notificationService.subscribe([eventname], "my-service")`
The above class is an example implementation of a NotificationService. It uses a fictional email service called `CoolEmailSender` to send emails to a customer whenever an order is placed. The `sendNotification` implementation gets the event name and fetches relevant data based on what event is being processed; in this case it retrieves an order, which is later used when requesting `CoolEmailSender` to dispatch an email. The address to send the email to is likewise fetched from the order.
The return type of `sendNotification` and `resendNotification` is an object with `to` and `data`. The `to` prop should identify the receiver of the notification, in this case an email, but it could also be a phone number, an ID, a channel name or something similar depending on the type of notification provider. The `data` prop contains the data as it was gathered when the notification was sent; the same data will be provided if the notification is resent at a later point.
When `resendNotification` is called the original Notification is provided along with a config object. The config object may contain a `to` property that can be used to overwrite the original `to`.
## Creating automated notification flows
When running an ecommerce store you typically want to send communication to your customers when different events occur, these include messages like order confirmations and shipping updates. With Medusa you can create transactional notifications as a reaction to a wide spectrum of events, allowing you to automate communication and processes. An example of a flow that can be implemented using Medusa's Notification API is automated return flows. Below is an outline of how an automated return flow might work.
- Customer requests a return with `POST /store/returns`
- Notification Service listens for `order.return_requested` and sends email to the customer with a return invoice and return label generated by fulfillment provider
- Customer returns items triggering `return.recieved`
- Notification Service listens for `return.received` and sends email to the customer with confirmation that their items have been received and that a refund has been issued.
Check out `medusa-plugin-sendgrid` for an Notification API implementation that works with Sendgrid.

View File

@@ -1,6 +1,10 @@
---
title: Plugins in Medusa
---
# Plugins
The purpose of this guide is to give an introduction to the structure of a plugin and the steps required to create one. It builds upon our article describing the process of [adding custom functionality](https://docs.medusa-commerce.com/tutorials/adding-custom-functionality). It can be seen as the proceeding steps for extracting your custom functionality to a reusable package for other developers to use.
The purpose of this guide is to give an introduction to the structure of a plugin and the steps required to create one. It builds upon our article describing the process of [adding custom functionality](https://docs.medusa-commerce.com/tutorial/adding-custom-functionality). It can be seen as the proceeding steps for extracting your custom functionality to a reusable package for other developers to use.
## What is a plugin?

View File

@@ -1,4 +1,4 @@
# Quick Start w. Docker
# Quickstart w. Docker
This quick start is intended for developers, that have already configured their local development environment and familiarised them selves with all the technologies and frameworks used throughout the Medusa eco-system.

View File

@@ -0,0 +1,37 @@
# Quickstart
This quickstart is intended for experienced developers, that are accustomed with concepts like JavaScript, Node.js, SQL and the command line. For a more gentle introduction, see our tutorial on [how to set up your development environment](https://docs.medusa-commerce.com/tutorial/set-up-your-development-environment).
## Getting started
1. **Install Medusa CLI**
```bash
npm install -g @medusajs/medusa-cli
```
2. **Create a new Medusa project**
```
medusa new my-medusa-store --seed
```
3. **Start your Medusa engine**
```bash
medusa develop
```
4. **Use the API**
```bash
curl localhost:9000/store/products | python -m json.tool
```
After these four steps and only a couple of minutes, you now have a complete commerce engine running locally. You may now explore [the documentation](https://docs.medusa-commerce.com/api) to learn how to interact with the Medusa API. You may also add [plugins](https://github.com/medusajs/medusa/tree/master/packages) to your Medusa store by specifying them in your `medusa-config.js` file.
## What's next?
### Set up a storefront for your Medusa project
We have created two starters for you that can help you lay a foundation for your storefront. The starters work with your new server with minimal configuration simply clone the starters from here:
- [Nextjs Starter](https://github.com/medusajs/nextjs-starter-medusa)
- [Gatsby Starter](https://github.com/medusajs/gatsby-starter-medusa)
### Link you local development to Medusa Cloud (Coming soon!)
With your project in local development you can link your Medusa instance to Medusa Cloud - this will allow you to manage your store, view orders and test out the amazing functionalities that you are building. [Get started here](https://docs.medusa-commerce.com/tutorial/linking-your-local-project-with-medusa-cloud).

View File

@@ -1,10 +1,11 @@
---
title: Set up your development environment
title: 0. Set up your development environment
---
# Set up your development environment
## Introduction
Welcome to Medusa - we are so excited to get you on board!
This tutorial will walk you through the steps to take to set up your local development environment. You will familiarize yourself with some of the core parts that make Medusa work and learn how to configure your development environment. Furthermore you will be introduced to how the plugin architecture works and how to customize your commerce functionalities with custom logic and endpoints.
@@ -12,11 +13,12 @@ This tutorial will walk you through the steps to take to set up your local devel
As a final part of the tutorial you will be linking your local project to Medusa Cloud where you can leverage advanced tools that make it easy to develop, test and deploy your Medusa project.
## Background Knowledge and Prerequisites
This tutorial aims to be as inclusive as possible so that most people with a bit of web development exeperience will be able to follow along and understand what is going on. In case you are completely new to programming and are just setting out to start working on your first project it will be helpful to familiarize yourself with a couple of the technologies that Medusa is build on
- **JavaScript**: The programming language that Medusa is written in. It is the language that runs in your browser to create dynamic web applications and has over the past decade gained a lot of traction as a backend language. If you wish to customize or extend Medusa it is highly recommended that you learn how JavaScript works. You can learn more about JavaScript with the [Basic JavaScript course from freeCodeCamp.](https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/#basic-javascript)
- **SQL & Postgresql**: Medusa uses the relational database PostgreSQL as the database layer where data is persisted. To understand how different entities relate to each other in Medusa it is helpful to have a good understanding of SQL. You can learn more about SQL and relational databases with the [SQL and Databases course from freeCodeCamp.](https://www.freecodecamp.org/news/sql-and-databases-full-course/)
- The **command line**: The command line is a text interface for your computer. It is used to run commands such as starting a program, performing a task or interfacing with the files on your computer. If you have never used the command line before you can check out [this tutorial](https://www.learnenough.com/command-line-tutorial) to get the basics in place.
- The **command line**: The command line is a text interface for your computer. It is used to run commands such as starting a program, performing a task or interfacing with the files on your computer. If you have never used the command line before you can check out [this tutorial](https://www.learnenough.com/command-line-tutorial) to get the basics in place.
To get a further understanding of what powers Medusa you can lookup these concepts:
@@ -25,6 +27,7 @@ To get a further understanding of what powers Medusa you can lookup these concep
- [**Idempotency Keys**](https://brandur.org/idempotency-keys)
## Installations
To get your development environment ready you need to install the following tools:
- Node.js
@@ -34,11 +37,13 @@ To get your development environment ready you need to install the following tool
- Medusa CLI
### Node.js
Node.js is an environment that can execute JavaScript code on outside of the browser making it possible to run on a server. Node.js is the environment that makes it possible for Medusa to run so you must install Node.js on your computer to start Medusa development.
Node.js has a bundled package manager called npm. npm helps you install "packages" which are small pieces of code that you can leverage in your Node.js applications. Medusa's core is itself a package distributed via npm and so are all of the plugins that exist around the core. [You can install Node.js from here.](https://nodejs.org/en/)
If you prefer using something like homebrew you can also run:
```
brew install node
```
@@ -46,7 +51,8 @@ brew install node
> **Mac users**: Make sure that you have Xcode command line tools installed; if not run `xcode-select --install`
### Git
Git is a version control system that keeps track on files within a project and makes it possible to do things like going back in history if you have made mistakes or collaborate with teammates without overriding each other's work. Almost all developers use Git for version control. Medusa uses git behind the scenes when you create a new project so you'll have to install it on your computer to get started.
Git is a version control system that keeps track on files within a project and makes it possible to do things like going back in history if you have made mistakes or collaborate with teammates without overriding each other's work. Almost all developers use Git for version control. Medusa uses git behind the scenes when you create a new project so you'll have to install it on your computer to get started.
If you are a Mac user you will already have Git installed as part of the Xcode command line tools, but for good measure check out installation of Git on different systems below:
@@ -55,9 +61,11 @@ If you are a Mac user you will already have Git installed as part of the Xcode c
- [Install Git on Linux](https://www.atlassian.com/git/tutorials/install-git#linux)
### PostgreSQL
PostgreSQL is an open-source relational database system with more than 30 years of active development. It is robust, reliable and ensures data integrity so there's no need to worry about those when you scale your project. Medusa uses PostgreSQL as its database and you will need to install it on your computer to get going. [Install PostgreSQL from here.](https://www.postgresql.org/download/).
If you prefer to use homebrew you may install PostgreSQL by running:
```
brew install postgresql
brew services start postgresql
@@ -65,25 +73,32 @@ createdb
```
### Redis
Redis is an open-source in memory data structure store which is used in Medusa to emit messages in the system and cache data. [Install Redis from here.](https://redis.io/download)
If you prefer to use homebrew you may install Redis by running:
```
brew install redis
brew services start redis
```
### Medusa CLI
The final installation to do to get started with Medusa is the Medusa CLI, which is an npm package you can install globally on your computer to get instant access to commands that help you manage and run your Medusa project. As the Medusa CLI is distributed as an npm package it is very easily installed by running:
```
npm install -g @medusajs/medusa-cli
```
```
We like to use Yarn instead of npm; if you wish to do the same you can install the CLI with:
```
yarn global add @medusajs/medusa-cli
```
### Text editor
If you don't already have a text editor of choice you should find one you like - here is a couple of candidates:
- [Neovim](https://neovim.io/) (if you are super oldschool there's also plain [Vim](https://www.vim.org/))
@@ -93,9 +108,11 @@ If you don't already have a text editor of choice you should find one you like -
It is not important which editor you use as long as you feel comfortable working with it.
## Medusa Cloud account
As the final step in this part of the tutorial you should create a Medusa Cloud account. Medusa Cloud is the platform that works with Medusa; the platform is where you view and manage your store, but is also a key part of the development process as you will be linking your local project to the platform so that you can manage your store while in development.
[Sign up for Medusa Cloud](https://app.medusa-commerce.com)
## Summary
## Summary
You now have all required software installed on your computer and have been introduced to a bit of our tech stack. In the next part of this tutorial we will be setting up a Medusa project for the first time and start making API requests.

View File

@@ -1,6 +1,11 @@
---
title: 1. Creating your Medusa server
---
# Creating your Medusa server
## Introduction
With the required software installed on your computer you are ready to start working on your first Medusa project.
In this part of the tutorial we will setup the skeleton for a Medusa store and will be making the first requests to your Medusa server.
@@ -8,6 +13,7 @@ In this part of the tutorial we will setup the skeleton for a Medusa store and w
Once you have completed this part of the tutorial you will have a powerful backend for digital commerce experiences. The server will be capable of handling orders, ensuring payments are going through, keeping basic product and customer data in sync, etc. You can use on of the frontend starters to quickly hook up your server to a presentation layer ([Gatsby](https://github.com/medusajs/gatsby-starter-medusa) or [Next](https://github.com/medusajs/nextjs-starter-medusa)).
## Setup a Medusa project
With Medusa CLI installed it is very easy to setup a new Medusa project, with the `new` command. In your command line run:
```shell
@@ -15,6 +21,7 @@ medusa new my-medusa-server --seed
```
The command will do a number of things:
- build a new project in a folder called my-medusa-server
- install the dependencies through yarn or npm
- setup a new git environment for version controlling your project
@@ -22,6 +29,7 @@ The command will do a number of things:
- the `--seed` flag indicates that the database should be populated with some test data after the project has been set up
If you navigate to the root folder of your new project you will see the following files in your directory:
```
.
├── node_modules
@@ -34,14 +42,17 @@ If you navigate to the root folder of your new project you will see the followin
├── README.md
└── package.json
```
There is not a lot of files needed to get your Medusa store setup and this is all due to the fact that the main Medusa core (`@medusajs/medusa`) is installed as a dependency in your project giving you all the fundamental needs for a digital commerce experience.
Much of Medusa's power lies in the `medusa-config.js` which is the file that configures your store and orchestrates the plugins that you wish to use together with your store. There are some different types of plugin categories such as payment plugins, notification plugins and fulfillment plugins, but plugins can contain any form of extension that enhances your store.
There is not a lot of files needed to get your Medusa store setup and this is all due to the fact that the main Medusa core (`@medusajs/medusa`) is installed as a dependency in your project giving you all the fundamental needs for a digital commerce experience.
Much of Medusa's power lies in the `medusa-config.js` which is the file that configures your store and orchestrates the plugins that you wish to use together with your store. There are some different types of plugin categories such as payment plugins, notification plugins and fulfillment plugins, but plugins can contain any form of extension that enhances your store.
For customizations that are more particular to your project you can extend your Medusa server by adding files in the `api` and `services` directories. More about customizing your server will follow in the following parts.
## Starting your Medusa server
After your project has been set up with `medusa new`, you can run the following commands to start your server:
```shell
cd my-medusa-server
medusa develop
@@ -49,27 +60,31 @@ medusa develop
If you ran the new command with the `--seed` flag you will already have products available in your store. To view these you can run the following command in your command line:
```shell
curl -X GET localhost:9000/store/products | python -m json.tool
```
## What's next?
At this point you are all set to start creating amazing digital commerce experiences. You can take a number of different routes from here and the next part of this tutorial will revolve around creating custom functionality within your Medusa project.
At this point you are all set to start creating amazing digital commerce experiences. You can take a number of different routes from here and the next part of this tutorial will revolve around creating custom functionality within your Medusa project.
Other options you could take are:
### Add a frontend to your server
We have created two starters for you that can help you lay a foundation for your storefront. The starters work with your new server with minimal configuration simply clone the starters from here:
- [Nextjs Starter](https://github.com/medusajs/nextjs-starter-medusa)
- [Gatsby Starter](https://github.com/medusajs/gatsby-starter-medusa)
### Browse the API reference
In the API reference docs you can find all the available requests that are exposed by your new Medusa server. Interacting with the API is the first step to creating truly unique experiences.
### Setup Stripe as a payment provider (Guide coming soon)
One of the first things you may want to do when building out your store would be to add a payment provider. Your starter project comes with a dummy payment provider that simply fakes payments being processed. In the real world you want a payment provider that can handle credit card information securely and make sure that funds are being transfered to your account. Stripe is one of the most popular payment providers and Medusa has an official plugin that you can easily install in your project.
## Summary
In this part of the tutorial we have setup your first Medusa project using the `medusa new` command. You have now reached a key milestone as you are ready to start building your Medusa store; from here there are no limits to how you can use Medusa as you can customize and extend the functionality of the core. In the next part of the tutorial we will be exploring how you can add custom services and endpoints to fit your exact needs.
In this part of the tutorial we have setup your first Medusa project using the `medusa new` command. You have now reached a key milestone as you are ready to start building your Medusa store; from here there are no limits to how you can use Medusa as you can customize and extend the functionality of the core. In the next part of the tutorial we will be exploring how you can add custom services and endpoints to fit your exact needs.

View File

@@ -1,44 +1,51 @@
---
title: 2. Adding custom functionality
---
# Adding custom functionality
## Introduction
In the previous part of the tutorial we set up your Medusa project using the `medusa new` and started your Medusa server locally. In this part we will start adding some custom functionality that extends the core. In particular this tutorial will take you through adding custom serverices, custom endpoints and subscribers. The custom functionality that we will be adding will create an endpoint called `/welcome/:cart_id` which customers of your store can use to opt-in to receiving a welcome in their email inbox after completing their order.
The custom functionality will do a number of things:
- Create a custom service that handles the logic around opting in. The service will ensure that only first time buyers will receive a welcome.
- Create a custom endpoint at `/welcome/:cart_id` which will take a `optin` parameter as part of its request body, and call our custom service.
- Create a subscriber that listens for the `order.placed` event and tells the custom service to send a welcome.
## Services
We will begin our custom implementation by adding a custom service. In you project create a new file at `/src/services/welcome.js`. Open the newly created file and add a class:
```javascript
import { BaseService } from "medusa-interfaces"
import { BaseService } from "medusa-interfaces";
class WelcomeService extends BaseService {
constructor({}) {
super()
super();
}
async registerOptin(cartId, optin) {}
async sendWelcome(orderId) {}
}
export default WelcomeService
export default WelcomeService;
```
We will be filling out each of the methods in turn, but before we get to that it should be noted that placing files in `/src/services` has a special meaning in Medusa projects. When Medusa starts up it will look for files in this folder and register exports from these files to the global container. The global container holds all services and repositories in your Medusa project allowing for dependency injection. Dependency injection is a software development technique in which objects only receive other objects that it depends upon.
We will be filling out each of the methods in turn, but before we get to that it should be noted that placing files in `/src/services` has a special meaning in Medusa projects. When Medusa starts up it will look for files in this folder and register exports from these files to the global container. The global container holds all services and repositories in your Medusa project allowing for dependency injection. Dependency injection is a software development technique in which objects only receive other objects that it depends upon.
### `constructor`
We will see dependency injection in action now when implementing the constructor:
```javascript
constructor({ cartService, orderService }) {
super()
this.cartService_ = cartService
this.orderService_ = orderService
}
```
@@ -48,6 +55,7 @@ In the constructor we specify that our `WelcomeService` will depend upon the `ca
> Note: Just like we can depend on the `cartService` and `orderService` other services will be able to depend on our newly created `WelcomeService`. The registration name of our service is the camelCased version of our file name with the registration type appended. I.e. `/src/services/welcome.js` -> `welcomeService`.
### `registerOptin`
The `registerOption` function will take to arguments: `cartId` and `optin`, where `cartId` holds the id of the cart that we wish to register optin for and `optin` is a boolean to indicate if the customer has accepted or optin or not. We will save the `optin` preferences in the cart's `metadata` field, so that it can be persisted for the future when we need to evaluate if we should send the welcome or not.
```javascript
@@ -55,17 +63,19 @@ async registerOptin(cartId, optin) {
if (typeof optin !== "boolean") {
throw new Error("optin must be a boolean value.")
}
return await this.cartService_.update(cartId, {
metadata: { welcome_optin: optin }
})
}
```
The `registerOptin` implementation simply validates that the provided argument is of the correct type and calls the CartService function `update`. `update` takes two arguments: the first is the id of the cart to update and the second is an object that with the key/value pairs that we want to update. In this case we are updating the metadata on the cart. The `metadata` field on the cart is itself an object so we need to pass an object when updating this field.
> Note: Most entities in Medusa have a `metadata` field that can be used for customizations or integrations when it is necessary to persist some data relating to the entity. Metadata cannot be overridden by other plugins.
### `sendWelcome`
The final function to implement in our class is the `sendWelcome` function that takes one argument `orderId` which holds the id of an order that we will evaluate whether to send a welcome for. In the implementation we leverage that when an order is created from a cart all the cart's metadata is copied to the order. We can therefore check `metadata.welcome_optin` to evaluate if the customer has allowed us to send a welcome to their email.
```javascript
@@ -73,19 +83,19 @@ async sendWelcome(orderId) {
const order = await this.orderService_.retrieve(orderId, {
select: ["email", "customer_id", "metadata"]
})
const prevOrders = await this.orderService_.list({
customer_id: order.customer_id
}, {
select: ["id"]
})
if (prevOrders.length > 1) {
// We only send welcomes to new customers. This customer
// has already completed an order before so we can stop.
return
return
}
if (order.metadata && order.metadata.welcome_optin) {
// Customer opted in so we should send an email
return await someEmailSender.send({
@@ -99,7 +109,7 @@ async sendWelcome(orderId) {
In the above implementation we are first retrieving the order that we need to check if we should send a welcome for. We are selecting only the fields that we need. In this case the `email` on the order, we will use this if we need to send out the welcome email, the `customer_id` which is used to determine if the customer has completed prior orders and `metadata` to check if the customer opted in to receiving the welcome email.
After retrieving the order we list all orders that have the same `customer_id` as the order we just retrieved. We are only interested in the count of these orders so it is sufficient for us to just select the ids of these orders.
After retrieving the order we list all orders that have the same `customer_id` as the order we just retrieved. We are only interested in the count of these orders so it is sufficient for us to just select the ids of these orders.
We then check if the number of previous orders is 0, indicating that the customer has not previously purchased anything from our store. If the number of previous orders is greater than 0 we can exit our function prematurely as we only send welcomes to new customers.
@@ -110,57 +120,59 @@ The final part of the implementation checks if the `welcome_optin` metadata has
We have completed the implementation of our custom service and we will now be able to call it from elsewhere in our project.
## Endpoints
Similarly to the `/src/services` directory, the `/src/api` directory has a special meaning in Medusa. Exports from this directory are assumed to be functions that return an express router instance that will be registered on the internal express app that Medusa creates when starting your server. This allows you to create custom endpoints for custom functionality. We will use this to create the custom endpoint that customers can use to give there welcome opt-in.
Create a new file at `/src/api/index.js` and add the following controller:
```javascript
import { Router } from "express"
import bodyParser from "body-parser"
import { Router } from "express";
import bodyParser from "body-parser";
export default () => {
const app = Router()
const app = Router();
app.post("/welcome/:cart_id", bodyParser.json(), async (req, res) => {
// TODO
})
return app
}
});
return app;
};
```
### Controller implementation
Our endpoint controller's implementation will be very simple. It will extract the `id` from the path paramater and the `optin` flag from the request body. We will then use these values to call our the `WelcomeService`, which will take care of updating the cart metadata for later.
```javascript
app.post("/welcome/:cart_id", bodyParser.json(), async (req, res) => {
const { cart_id } = req.params
const { optin } = req.body
// Validate that the optin value was provided.
// If not respond with a Bad Request status
if (typeof optin !== "boolean") {
res.status(400).json({
message: "You must provide an boolean optin value in the request body"
})
return
}
const welcomeService = req.scope.resolve("welcomeService")
try {
await welcomeService.registerOptin(cart_id, optin)
res.status(200).json({
success: true
})
} catch (err) {
// This is not supposed to happen.
res.status(500).json({
message: "Something unexpected happened."
})
}
})
const { cart_id } = req.params;
const { optin } = req.body;
// Validate that the optin value was provided.
// If not respond with a Bad Request status
if (typeof optin !== "boolean") {
res.status(400).json({
message: "You must provide an boolean optin value in the request body",
});
return;
}
const welcomeService = req.scope.resolve("welcomeService");
try {
await welcomeService.registerOptin(cart_id, optin);
res.status(200).json({
success: true,
});
} catch (err) {
// This is not supposed to happen.
res.status(500).json({
message: "Something unexpected happened.",
});
}
});
```
In the implementation above we are first validating that the request body is structured correctly so that we can proceed with our opt-in registration. If the validation fails we respond with 400 Bad Request which is an HTTP code that indicates that the client that sent the request has not provided the correct values.
@@ -170,10 +182,13 @@ After validation is passed we leverage Medusa's container system again to fetch
We put our `registerOptin` function call in a try-catch block to ensure that we can handle unexpected errors. If the call to `registerOptin` succeeds we respond with 200 OK and if for some reason we encounter an error we respond with 500 Internal Server Error.
We have now completed the implementation necessary to complete opt-in registration on a cart. To test that your implementation is working correctly start up your Medusa server using: `medusa develop`. You can now send requests to the server, first create a new cart using:
```shell
curl -X POST localhost:9000/store/carts | python -m json.tool
```
The copy the cart id (the one that starts with `cart_`) and use it to opt-in to the welcome pack using:
```shell
curl -X POST \
-H 'Content-Type: application/json' \
@@ -186,7 +201,9 @@ The endpoint should respond with `{"success":true}`. If you wish to check that t
```shell
curl -X GET localhost:9000/store/carts/[copied cart id] | python -m json.tool
```
The response should contain the cart with the metadata field set like this:
```
{
"cart": {
@@ -200,14 +217,15 @@ The response should contain the cart with the metadata field set like this:
```
## Subscribers
The final thing that we will add in this part of the tutorial is the subscriber that listens for the `order.placed` event and sends out emails if the user has opted in for welcomes. Again we will leverage one of the special directories in Medusa that makes dependency injection easy and automatic. The directory to place a file in this time is the `/src/subscribers` directory, which treats exports as subscribers and makes sure the inject dependencies in a similar fashion to what we saw with services. To get started with our implementation create a file at `/src/subscribers/welcome.js` and add the following:
```javascript
class WelcomeSubscriber {
constructor({ welcomeService, eventBusService }) {
this.welcomeService_ = welcomeService
this.welcomeService_ = welcomeService;
eventBusService.subscribe("order.placed", this.handleWelcome)
eventBusService.subscribe("order.placed", this.handleWelcome);
}
handleWelcome = async (data) => {
@@ -220,16 +238,18 @@ export default WelcomeSubscriber;
The implementation above is all that is needed to automate the `sendWelcome` function to be called every time a new order is created. The subscriber class here delegates all of the business logic to the `sendWelcome` function, where we are checking for opt-in and first time buyers.
If we take a closer look at the constructor it will seem pretty familiar. Just like with our custom service, we are indicating which dependencies we would like to receive and Medusa will make sure to pass these on as the first argument to our constructor. In this case we are depending on the `welcomeService` which is used to take care of sending welcomes, and the `eventBusService` which is a core service in Medusa that handles events across your server allowing you to subscribe to events of interest. In this case we are using the `eventBusService` to subscribe to the `order.placed` event which is emitted every time a new order is created. The subscription is registered by the `eventBusService.subscribe` function which takes the event name to subscribe to as its first argument and a callback function to call when the event occurs, as its second argument.
If we take a closer look at the constructor it will seem pretty familiar. Just like with our custom service, we are indicating which dependencies we would like to receive and Medusa will make sure to pass these on as the first argument to our constructor. In this case we are depending on the `welcomeService` which is used to take care of sending welcomes, and the `eventBusService` which is a core service in Medusa that handles events across your server allowing you to subscribe to events of interest. In this case we are using the `eventBusService` to subscribe to the `order.placed` event which is emitted every time a new order is created. The subscription is registered by the `eventBusService.subscribe` function which takes the event name to subscribe to as its first argument and a callback function to call when the event occurs, as its second argument.
In this case we are using the `handleWelcome` function as our callback. The callback function receives the data that is passed for the event. The `order.placed` event contains the order id in the data object which is what the `welcomeService` needs to handle the sending logic so we simply call `sendWelcome` with `data.id`.
You can now start up your server and test out the subscriber. Given that you have opted in to receiving welcome emails you can complete an order and you should receive an email with the welcome message.
## Summary
You have now learned how to add custom functionality to your Medusa server, which is one of the most powerful features of the Medusa core. The example above is quite simple, yet we have covered many of the customization capabilities available. We first looked at how to include custom business logic in Medusa by using services and dependency injection. Afterwards we put that logic to use when implementing our custom endpoint and in the final part of the tutorial we added some simple automation that handles sending the welcome message on every new order.
### What's next?
You have now been introduced to many of the key parts of Medusa and with your knowledge of customization you can now begin creating some really powerful commerce experiences. If you have an idea for a cool customization go ahead and make it right now! If you are not completely ready yet you can browse the reference docs further.
In the next part of this tutorial we will look into linking your local project with Medusa Cloud to make develpment smoother while leveraging the powerful management tools that merchants use to manage their Medusa store.

View File

@@ -1,41 +1,57 @@
---
title: 3. Linking your local project with Medusa Cloud
---
# Linking your local project with Medusa Cloud
## Introduction
In this part of the tutorial you will learn how to link your local Medusa project to Medusa Cloud. Doing this will enhance you development experience as you will closely mimic how Medusa would work in a production environment. Furthermore, you will be able to easily manage orders and products in your local project directly from Medusa Cloud. Linking Medusa is easily done with the Medusa CLI which you should already be installed when you set up your development environment.
## Creating a Medusa Cloud account and CLI authentication
To link your local project you must first authenticate to Medusa using your CLI. Authenticating with the CLI is done by running:
```shell
medusa login
```
The `login` command will open your browser where you will be presented with the authentication options available. If you already have an account you can simply authenticate and you CLI will automatically be authenticated.
If you don't have an account yet you can easily create one as part of the CLI authentication. First, choose the method that you want to login with we support logging in with GitHub, Google or simple email/password authentication. If choosing GitHub or Google without an existing account you will be taken straight to the sign up form where you can fill in your details and create an account. If you wish to sign up with an email/password combination simply click "Log in with email" and at the bottom of the form click "Sign up". Once you have filled out the sign up form your CLI will be authenticated.
To test that you have successfully authenticated you can run:
```shell
medusa whoami
```
This will print out your account details.
## Linking your local project
Once you have authenticated your CLI for your Medusa Cloud account you are ready to perform local linking. To link your project first naviagate to your project root - where your `medusa-config.js` file is. You can now run the following command:
```shell
medusa link --develop
```
The `link` command will first check that you have authenticated your CLI which we did in the previous step. Then it will perform the local linking, which essentially adds an admin user in the local database specified in `medusa-config.js`. Finally, your browser will open Medusa Cloud to perform the linking there, which tells Medusa Cloud where your local server is running. On succesful linking in the browser you will see a confirmation page with a "Go to orders" button. If you click this button you will be taken to an overview of the orders made in your local project.
You should note that the `--develop` flag is optional for the `link` command. If provided it tells the CLI to start up your server after linking is completed; you may leave it out if you'd rather start your server separately.
You should note that the `--develop` flag is optional for the `link` command. If provided it tells the CLI to start up your server after linking is completed; you may leave it out if you'd rather start your server separately.
> Note: For local linking to work you must make sure to have your CORS settings configured correctly. This is done by adding `https://app.medusa-commerce.com` to your `cors_admin` config in `medusa-config.js`.
> Note: If you change the port that your local server is running on you will have to run `medusa link` again. `medusa link` uses your `PORT` environment variable to specify where Medusa Cloud should look for your local server.
## Summary
You are now able to run a local development environment that is nearly identical to a production environment. This is made possible by linking your local project using the `medusa link` command. In Medusa Cloud you will be able to manage your store and test the features you are developing.
### What's next?
You are all set to start developing on your Medusa project. If you haven't already now would be a good time to add a front-end to your Medusa server. We have two starters that you can use to get going:
- [Nextjs Starter](https://github.com/medusajs/nextjs-starter-medusa)
- [Gatsby Starter](https://github.com/medusajs/gatsby-starter-medusa)

View File

@@ -1,89 +0,0 @@
---
title: Getting started
---
# Quick Start w. Docker
This quick start is intended for developers, that have already configured their local development environment and familiarised them selves with all the technologies and frameworks used throughout the Medusa eco-system.
If this is not the case, please head over to our Getting Started tutorial for a thorough walkthrough.
## Introduction
With all the tools and technologies in place, let's get started by setting up a default project. Our starter is shipped with a very basic configuration, that includes the following plugins:
- Stripe as payment provider
- SendGrid as email notification provider
- Manual fulfilment as fulfilment provider
Additionally, we will spin up a PostgreSQL database and a Redis server, both required for Medusa to run. In this quick start, we will use docker to seamlessly set up these resources.
## Get started
1. Clone our starter project from Github
```bash
git clone https://github.com/medusajs/medusa-starter-default.git my-medusa-starter
```
2. Once cloned, we will jump into our project directory and get started with our configuration.
```bash
cd my-medusa-starter
```
3. Get your environment variables ready using our template
```bash
mv .env.template .env
```
4. Setup accounts for included plugins. This step is optional but required for placing orders.
Create a Stripe account and add your API key and webhook secret to `.env`
Create a SendGrid account and add your API key to `.env`
```bash
...
STRIPE_API_KEY="some_stripe_key"
STRIPE_WEBHOOK_SECRET="some_webhook_secret"
SENDGRID_API_KEY="some_sendgrid_key"
..
```
5. Start your server
```bash
docker-compose up --build
```
We will use docker-compose and Docker to start up our development environment. Running the above command will do the following:
1. Build images for our Medusa project, a PostgreSQL database and a Redis server
2. Run migrations for our newly created database
3. Seed our database with some entities, that will allow us to easily get started.
These include:
- A user with email `admin@medusa-test.com` and password `supersecret`
- A region called Default Region with a small subset of countries
- A shipping option called Standard Shipping, that costs 10 EUR
- A product called Cool Test Product
- A variant of that product that costs 195 EUR
Once done, our server will be accessible at `http://localhost:9000`.
## Try it out
Let's try out our Medusa server by fetching some products.
```bash
curl -X GET localhost:9000/store/products | python -m json.tool
```
## What's next?
Add custom endpoint to your Medusa project (Insert link)
Install and configure additional plugins (Insert link)
Build a storefront using our Gatsby starter (Insert link)