# Routing

Install the router and utilities:

```bash
bun add @stricjs/router @stricjs/utils
```

The router component provides the routing part for Stric, like Express or Fastify.

The utilities component has helpful utilities to parse and handle requests.

## Define routes

You can define a route using `[method](path, handler)`, for instance:

```typescript
import { Router } from '@stricjs/router';  

export default new Router()
    .get('/', () => new Response('Hi'));
```

In the above example, we create a new router and this router will respond with `Hi` on every `GET` request to pathname `/`. The router can be served with `export default` or `Bun.serve` directly because it is a serve options object.

### All method handlers

To add a handler for all methods, use `app.all` with the same parameter as above.

```typescript
import { Router } from '@stricjs/router';

export default new Router()
    .all('/', () => new Response('Hi'));
```

## Request methods

You can define a route with another request method as well.

```typescript
import { Router } from '@stricjs/router';  

export default new Router()
    // You should use new Response(JSON.stringify(...), { headers: { ... } })
    // for it to be faster. This example provides a clean way to do this
    .post('/json', () => Response.json({ hi: 'there' }));
```

Compares to the first example, this example add another handler which will run on every `POST` request to pathname `/json`. This handler will return an object as a response.

## Parametric routes

You can parametric routes to retrieve data from URLs, works like Express and Fastify routes.

The type of `req.params` is inferred directly based on the path.

```typescript
import { Router } from '@stricjs/router';  

export default new Router()
    .get('/id/:id', req => new Response(req.params.id));    
```

In this example, the server will respond to every route that matches `/id/:id` with the specified `id` parameter value in the URL. For example, if we send a `GET` request to pathname `/id/90` we will get `90` as a response.

## Wildcard

You can use the wildcard `*` to match the rest of the path.

```typescript
import { Router } from '@stricjs/router';  

export default new Router()
    .get('/private/*', req => 
        new Response(`Cannot access /private/${req.params['*']}`)
    );
```

This will respond to every request pathname starts with `/private/`.

## Body parsing

Stric has a set of predefined body parser you can use.

```typescript
import { Router } from '@stricjs/router';

export default new Router()
    .post('/text', req => {
        // Use the parsed body here (it has type hint)
        req.data;
    }, { body: 'text' });
    
// More parsers:
{ body: 'json' } // Parse to JSON
{ body: 'blob' } // Parse to Blob
{ body: 'form' } // Parse to FormData
{ body: 'buffer' } // Parse to ArrayBuffer
{ body: 'none' } // Don't parse body. This is the default value
```

## Query parsing

The `req.query` parameter returns the query start index, include the `?` character. You can parse query with `@stricjs/utils`:

```typescript
import { Router } from '@stricjs/router';  
import { query as parse } from '@stricjs/utils';

export default new Router()
    .get('/id/:id', req => {
        // If the query does not exist only respond with the ID
        if (req.query === -1) return new Response(req.params.id);

        // Get the 'name' parameter from query if query exists
        return new Response(
            req.params.id + ' ' + parse(
                // Get the query string without '?'
                req.url.substring(req.query + 1)
            ).name
        );
    });
```

## Guarding

Guarding routes and validating data.

### Routes

Guard routes work like wildcard but these routes are invoked first to check whether a specific sub-route should be handled.&#x20;

```typescript
import { Router } from '@stricjs/router';

export default new Router()
    // Return null to tell the router to use the 404 handler
    .guard('/', req => req.path === 'forbidden' ? null : true)
    .get('/', () => new Response('Hi'))
    .post('/json', req => req.json().then(Response.json))
    .get('/forbidden', () => new Response('Never response'));
```

### Input validations

The `@stricjs/utils` component provides a simple and fast guard for checking user input.

```typescript
import { Router } from '@stricjs/router';
import { guard } from '@stricjs/utils';

const check = guard.create({ 
    name: 'str', // string
    age: 'num', // number
    address: '?str' // Optional string (prefix with ?)
    /*
        More things here, for example:
        data: {
            isRegistered: 'bool'
        }
    */
});

// Return the current object if the type matches, else null
// For this case it matches so it returns the passed object
check({
    name: 'Dave',
    age: 23
});

// Register a new type
guard.register('mycustomtype', (object: any) => {
    // Do validation here, should return true or false
});

/*
    Basic types:
    - 'str': string
    - 'num': number
    - 'bool': boolean
    - 'nil': null
    - 'undef': undefined
    - 'bf': Buffer
*/ 
```

Right now guard function is limited and does not support arrays (Arrays are very hard to compose).

## Router groups

Using groups to split the route handlers.

```typescript
import { Router, Group } from '@stricjs/router';

// IDs
const idList = {
    '0': 'a',
    '1': 'b',
    '2': 'c'
};

// Response stuff
const notFound = { status: 404 };
const msg = 'Welcome! Go to /search/:id to search for specific IDs';
const group = new Group('/search')
    .get('/:id', req => {
        if (req.params.id in idList)
            return new Response(idList[req.params.id]);
        return new Response('Item not found', notFound);
    });

// Router
export default new Router()
    .plug(group)
    .get('/', () => new Response(msg));
```

This is a simple example which create a new group with the root set to `/search`, so the actual path that is registered is `/search/:id`, not `:/id`.

## Special handlers

Stric provides a fast way to handle 404 when a route handler is not found.

```typescript
import { Router } from '@stricjs/router';

export default new Router()
    .get('/', () => new Response('Hi'))
    .use(404, req => { /* Maybe something here to return */ });
```

Call `use(404)` to use the default `404` handler, `use(404, handler)` to add a custom handler.

For error handling, you can use the default `500` handler or register a custom handler the same way as the `404` handler.

```typescript
import { Router } from '@stricjs/router';

export default new Router()
    .get('/', () => {
        throw new Error('Error');
    })  
    .use(500, err => new Response(err.message));
```

## Storing states

You can store states and methods for using in requests.

```typescript
import { Router } from '@stricjs/router';

export default new Router()
    .store('count', 0)
    // On every request increment count by one and return it as a response
    .get('/increment', (_, store) => new Response(
        String(++store.count)
    ));
```

All states are stored in an object which is passed as a reference to the handler as the second argument, which mean you can change the properties of the store but not the store itself.

## WebSocket

You can split routes for WebSocket handlers.

```typescript
import { Router } from '@stricjs/router';

export default new Router()
    .ws('/', {
        message(ws) {
            ws.send('Hi client!');
        }
    });
```

WebSocket routes cannot collide with other route handlers of the router, but you can still register route handlers with the same pathname but not `GET` method.

<details>

<summary>Details</summary>

* WebSocket handlers are stored in a list, which is then attached with the upgrade data when `server.upgrade(req, opts)` is called.
* The WebSocket handler is stored in the static route handlers list as a number which represents the index of the handler in the WebSocket handlers list.
* When the path matches, the WebSocket handler is attached with the current `Request` object as a property `_`. The request object will be sent to the WebSocket event handlers as attached data.
* Each WebSocket event handler will check if the specific handler for that event was registered. If it is registered the event handler will be executed.

</details>

## Optimizations

Here are some optimizations you can do to make your Stric application faster.

### Set the base URL&#x20;

You can specify the exact base URL of your app to make path parsing faster. Note that will not works correctly if your app has subdomains.

<details>

<summary>Details</summary>

* The `createFetch` function calculates the length of the `base` property.
* The calculated length actually is the start index of the path part, so we can inject it directly into the code to check for query start index faster.

</details>

```typescript
import { Router } from '@stricjs/router';

export default new Router({ base: 'http://localhost:3000' })
   .get('/', () => new Response('Hi')); 
```

### No path parsing

Set `parsePath` to `false` will skip slicing the path for matching routes and use the URL directly. This optimization will only work with the base optimization.

```typescript
import { Router } from '@stricjs/router';

export default new Router({ 
   base: 'http://localhost:3000', 
   parsePath: false 
}).get('/', () => new Response('Hi')); 
```

<details>

<summary>Details</summary>

* Normally `req.path` is parsed to check the pathname.
* If you disable path parsing `req.path` will not be usable.

</details>

### Faster query parsing

If you only need the value of a single key in the query, you can create a specific parser with `@stricjs/utils` to search for the value. This function will return the value without decoding.

```typescript
import { Router } from '@stricjs/router';
import { qs } from '@stricjs/utils';

// Only search for a single value of name
const parse = qs.searchKey('name');

export default new Router()
    .get('/', req => new Response(
        // Get the value of the name parameter if presented
        // If not presented this function will return null
        parse(req.url, req.query + 1)
    ));
```

### Using macros

Macros inject your code directly to your `fetch` without caching and calling the handler like usual, which can reduce response time. This feature should **only** be used for small handlers.

```typescript
import { Router, macro } from '@stricjs/router';

export default new Router()
    .get('/', macro(() => new Response('Hi')));
```

For returning a string response, macro has a shorthand.

```typescript
import { Router, macro } from '@stricjs/router';

export default new Router().get('/', macro('Hi'));
```

#### Limitations

Because macro code is injected directly to the `fetch` function, it has some limitations.

* Macros cannot access outside variables. To access variables outside the function scope you need to store it using `app.store()`.
* Macros code cannot use `await`. The fetch function is synchronous. You can return a promise, but can't use `await`.
* Macros need proper parameters name. Code in macros that directly use the request and store need to have the same name as the variables in `fetch`.
