Skip to content

Commit

Permalink
Merge pull request #196 from AthennaIO/develop
Browse files Browse the repository at this point in the history
update deps
  • Loading branch information
jlenon7 authored Mar 6, 2024
2 parents e8ce0c3 + cc45110 commit 146730d
Show file tree
Hide file tree
Showing 11 changed files with 265 additions and 52 deletions.
18 changes: 8 additions & 10 deletions docs/database/getting-started.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,13 @@ using a fluent query builder and the ORM.

## Installation

First of all you need to install `@athenna/database` package:
First of all you need to install `@athenna/database` package
and configure it. Artisan provides a very simple command to
install and configure the database library in your project.
Simply run the following:

```bash
npm i @athenna/database
```

Artisan provides a very simple command to configure the database
library in your project. Simply run the following:

```bash
node artisan configure @athenna/database
node artisan install @athenna/database
```

The database configurer will do the following operations in
Expand All @@ -39,7 +35,9 @@ your project:
- Add all database commands in your `.athennarc.json` file.
- Add all database template files in your `.athennarc.json` file.
- Add database environment variables to `.env`, `.env.test` and `.env.example`.
- Configure the `docker-compose.yml` file acordding to the database selected.
- Configure the `docker-compose.yml` file according to the database selected.
- Install libraries like `knex` and `pg`. It will always depends on the default
database you selected.

## Configuration

Expand Down
157 changes: 156 additions & 1 deletion docs/digging-deeper/mail.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,159 @@ See how to send emails in Athenna.

## Introduction

Coming soon
Sending email doesn't have to be complicated. Athenna provides a
clean, simple email API powered by the popular [nodemailer] package.
Right now Athenna provide drivers for sending email via SMTP, only
but in the future we will add support for Mailgun, Mailtrap,
Amazon SES, and sendmail.

## Installation

First of all you need to install `@athenna/mail` package
and configure it. Artisan provides a very simple command to
install and configure the mail library in your project.
Simply run the following:

```bash
node artisan install @athenna/mail
```

The mail configurer will do the following operations in
your project:

- Create the `mail.ts` configuration file.
- Add all mail providers in your `.athennarc.json` file.
- Add mail environment variables to `.env`, `.env.test` and `.env.example`.

## Configuration

Athenna's email services may be configured via your application's
`Path.config('mail.ts')` configuration file. Each mailer configured
within this file may have its own unique configuration and even
its own unique "transport", allowing your application to use different
email services to send certain email messages.

### Available mail drivers

Each mailer is powered by a "driver". The driver determines how
the mail will be transported. The following mail drivers are
available in every Athenna application. An entry for most of
these drivers is already present in your application's
`Path.config('mail.ts')` configuration file, so be sure to
review this file to become familiar with its contents:

| Driver name | Website | Built with |
|:------------|:----------------------------:|------------------------------------------------------:|
| `smtp` | https://nodemailer.com/smtp/ |[nodemailer](https://www.npmjs.com/package/nodemailer) |

:::note

Athenna has another driver called `fake` that is very helpful when running tests.
The `fake` driver got the same signature of all other drivers, but it don't execute
any operation when calling executors methods like `send()`, which is perfect to use
within the [`Mock`](/docs/testing/mocking) class. For more information
about the `FakeDriver`, take a look at the
[mocking mail documentation section.](/docs/testing/mocking#mocking-mail)

:::

## Sending mail

Let's see the simplest way to send a mail using Mail facade:

```typescript
import { Mail } from '@athenna/mail'

await Mail.from('[email protected]')
.to('[email protected]')
.text('Mail content')
.send()
```

You can add "to", "cc" and "bcc" recipientes by chaining
their respective method together:

```typescript
await Mail.from('[email protected]')
.to('[email protected]')
.cc('[email protected]')
.bcc('[email protected]')
.text('Mail content')
.send()
```

### Sending mail via a specific mailer

By default, Athenna will send email using the mailer configured
as the `default` mailer in your application's `mail` configuration
file. However, you may use the `mailer()` method to send a message
using a specific mailer configuration:

```typescript
await Mail.mailer('my-mailer')
.from('[email protected]')
.to('[email protected]')
.text('Mail content')
.send()
```

### Sending HTML and Markdown as content

To send HTML as the content of the mail, you can use the `html()`
method:

```typescript
await Mail.mailer('my-mailer')
.from('[email protected]')
.to('[email protected]')
.html('<h1>Mail content</h1>')
.send()
```

And for markdowns you can use the `markdown()` method:

```typescript
await Mail.mailer('my-mailer')
.from('[email protected]')
.to('[email protected]')
.markdown('# Mail content')
.send()
```

### Using view template as content

The mail component is integrated with the view component to be
able to render and send a view as the body of the email. To do
so you can use the `view()` method of the Mail facade:

```typescript
const userEmail = '[email protected]'

await Mail.from('[email protected]')
.to(userEmail)
.view('mail/welcome', { email: userEmail })
.send()
```

### Previewing mail templates in the browser

When designing a mailable's template, it is convenient to quickly
preview the rendered mailable in your browser like a typical
Edge template. For this reason, Athenna allows you to return any
mailable directly from a route closure or controller by using the
`response.view()` method, allowing you to quickly preview its
design without needing to send it to an actual email address:

```typescript title="Path.routes('http.ts')"
Route.get('/mailable', ({ response }) => {
return response.view('mail.welcome', { email: '[email protected]' })
})
```








4 changes: 4 additions & 0 deletions docs/getting-started/directory-structure.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ This directory does not exist by default, but will be created
for you if you execute the following command:

```bash
# To install the library and configure it
node artisan install @athenna/database

# To just configure the library
node artisan configure @athenna/database
```

Expand Down
14 changes: 7 additions & 7 deletions docs/rest-api-application/annotations.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import { Controller, type Context } from '@athenna/http'

@Controller()
export class UserController {
public async index(ctx: Context) {
return ctx.response.status(200).send({ status: 'ok' })
public async index(({ response }): Context) {
return response.status(200).send({ status: 'ok' })
}
}
```
Expand Down Expand Up @@ -80,8 +80,8 @@ import { Middleware, type Context } from '@athenna/http'

@Middleware()
export class UserMiddleware {
public async handle(ctx: Context) {
ctx.user = await User.find({ id: ctx.params.id })
public async handle(({ request, data }): Context) {
data.user = await User.find({ id: request.param('id') })
}
}
```
Expand Down Expand Up @@ -164,10 +164,10 @@ import { Interceptor, type Context } from '@athenna/http'

@Interceptor()
export class UserInterceptor {
public async intercept(ctx: Context) {
ctx.body.intercepted = true
public async intercept(({ response }): Context) {
response.body.intercepted = true

return ctx.body
return response.body
}
}
```
Expand Down
4 changes: 2 additions & 2 deletions docs/rest-api-application/controllers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ import { Context, Controller } from '@athenna/http'

@Controller()
export class UserController {
public async show({ response, params }: Context) {
return response.send(`User_${params.id}`)
public async show({ request, response }: Context) {
return response.send(`User_${request.param('id')}`)
}
}
```
Expand Down
18 changes: 9 additions & 9 deletions docs/rest-api-application/middlewares.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ import { Context, Middleware, MiddlewareContract } from '@athenna/http'

@Middleware()
export class EnsureApiKeyIsValid implements MiddlewareContract {
public async handle(ctx: Context): Promise<void> {
if (queries.apiKey !== 'my-api-key') {
public async handle(({ request }): Context): Promise<void> {
if (request.query('apiKey') !== 'my-api-key') {
throw new UnauthorizedException('Your api key does not match with application api key.')
}
}
Expand Down Expand Up @@ -108,8 +108,8 @@ import type { Context, MiddlewareContract } from '@athenna/http'

@Middleware({ isGlobal: true }) 👈
export class EnsureApiKeyIsValid implements MiddlewareContract {
public async handle(ctx: Context): Promise<void> {
if (queries.apiKey !== 'my-api-key') {
public async handle(({ request }): Context): Promise<void> {
if (request.query('apiKey') !== 'my-api-key') {
throw new UnauthorizedException('Your api key does not match with application api key.')
}
}
Expand Down Expand Up @@ -141,8 +141,8 @@ import type { Context, MiddlewareContract } from '@athenna/http'

@Middleware({ name: 'auth' }) 👈
export class EnsureApiKeyIsValid implements MiddlewareContract {
public async handle(ctx: Context): Promise<void> {
if (queries.apiKey !== 'my-api-key') {
public async handle(({ request }): Context): Promise<void> {
if (request.query('apiKey') !== 'my-api-key') {
throw new UnauthorizedException('Your api key does not match with application api key.')
}
}
Expand Down Expand Up @@ -198,10 +198,10 @@ import type { InterceptContext, InterceptorContract } from '@athenna/http'

@Interceptor()
export class InterceptMiddleware implements InterceptorContract {
public async intercept(ctx: InterceptContext): Promise<unknown> {
ctx.body.intercepted = true
public async intercept(({ response }): InterceptContext): Promise<unknown> {
response.body.intercepted = true

return ctx.body
return response.body
}
}
```
Expand Down
15 changes: 3 additions & 12 deletions docs/rest-api-application/request-context.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -400,15 +400,7 @@ Route.get('/welcome', ({ response }) => {
})
```

### The params object

The `params` object contains the actual HTTP params of the
request that is being handled by your application.

### The queries object

The `queries` object contains the actual HTTP queries of the
request that is being handled by your application.

### The data object

Expand Down Expand Up @@ -459,12 +451,11 @@ interface from `@athenna/http` package.

In [interceptors](/docs/rest-api-application/middlewares#intercept-middleware)
Athenna uses the `InterceptContext`. This context is quite
the same of `Context`, but it has additional properties
`body` and `status`.
the same of `Context`, but it has additional property `status`.

### Terminate middleware context

In [terminators](/docs/rest-api-application/middlewares#terminate-middleware)
Athenna set the `TerminateContext`. This context is quite
the same of `Context`, but it has additional properties
`body`, `status` and `responseTime`.
the same of `Context`, but it has additional properties
`status` and `responseTime`.
37 changes: 31 additions & 6 deletions docs/rest-api-application/routing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,35 @@ incoming request is matched with the correct route.

:::

## View routes

You may use the `Route.view()` method if you have a route handler
that only renders a view. It is a convenient shortcut to render
a view without defining an explicit handler:

```typescript
Route.view('/welcome', 'welcome')
```

The example above is just a shortcut for the following:

```typescript
Route.get('/welcome', ({ response }) => {
return response.view('welcome')
})
```

Optionally, you can pass the template data as the third argument,
just like in `response.view()` method:

```typescript
Route.view('/welcome', 'welcome', { name: 'lenon' })
```

## Redirect routes

If you are defining a route that redirects to another
`url`, you may use the `Route.redirect` method. This
`url`, you may use the `Route.redirect()` method. This
method provides a convenient shortcut so that you do not
have to define a full route or controller for performing
a simple redirect:
Expand All @@ -70,9 +95,9 @@ a simple redirect:
Route.redirect('/here', '/there')
```

By default, `Route.redirect` returns a `302` status code.
You may customize the status code using the optional
third parameter:
By default, `Route.redirect()` method returns a `302`
status code. You may customize the status code using
the optional third parameter:

```typescript
Route.redirect('/here', '/there', 301)
Expand Down Expand Up @@ -104,8 +129,8 @@ a user's ID from the URL. You may do so by defining route
parameters:

```typescript
Route.get('/user/:id', ({ response, params }) => {
return response.send({ user: `User ${params.id}` })
Route.get('/user/:id', ({ request, response }) => {
return response.send({ user: `User ${request.param('id')}` })
})
```

Expand Down
Loading

0 comments on commit 146730d

Please sign in to comment.