# Request Engine (http)

Xpresser RequestEngine (opens new window) is the class whose instance represents your current request and response when handling requests.

# Properties

Properties available on http methods are:

# req

# Type: Xpresser.Http.Request

http.req object represents the HTTP request and has properties for the request query string, parameters, body, HTTP headers, and so on.

Read more about req on expressjs.com (opens new window)

# res

# Type: Xpresser.Http.Response

http.res object represents the HTTP response that an Express app sends when it gets an HTTP request. Read more about res on expressjs.com (opens new window)

# params

# Type: Record<string, any>

http.params is an object containing properties mapped to the named route “parameters”. For example, if you have the route /user/:name, then the name property is available as http.params.name.
This object defaults to {}.

# route

# Type: {name: string, method: string, controller: string}

http.route holds the name, method & controller of the current request
For example:

{
  "name": "index",
  "method": "get",
  "controller": "AppController@index"
}

# Use Cases

In some situations you may want to point multiple requests to one controller action, http.route data will help your decide what action to take.

# Controller Action Example
# Controller Boot Example

If you make use of controller boot methods frequently then http.route.controller can help you decide what to boot for each method. For example

Note: http.route.controller will be spelled correctly in full, even if you used shorthand when declaring the route.

# store

Deprecated, Renamed to state.

# state

# Type: ObjectCollection

http.state serves as a state management for the current request. it is an instance of object-collection

// In a middleware
http.state.set("currentIp", "127.0.0.1");

// In your controller or else where.
const currentIp = http.state.get("currentIp");

# $query

# Type: ObjectCollection

http.$query holds your current request query data as a collection. if you don't want it as a collection then you can use http.req.query

// get ?page or return default 1
http.$query.get("page", 1)

// Pick only specified keys
http.$query.pick(["utm_campaign", "utm_campaign_id"]) 

# $body

# Type: ObjectCollection

http.$body holds your current request body data as a collection. if you don't want it as a collection then you can use http.req.body

// Get status or return default `pending`
http.$body.get("status", "pending")

// Pick only specified keys
http.$body.pick(["email", "password"]) 

# Methods

# $(): DollarSign

# Type: <K extends keyof DollarSign>(key: K) => DollarSign[K]

http.$ function serves a helper method for you to access your xpresser instance properties at any time. But it doesn't return the instance.

$.helpers.randomStr(10);
// will be
http.$("helpers").randomStr(10);

$.events.emit("User.loggedIn");
// will be
http.$("events").emit("User.loggedIn")

# $instance()

# Type: () => DollarSign

http.$instance() returns the current xpresser instance

const $ = http.$instance();

$.events.emit("User.loggedIn");

# addToBoot

# Type: (key: string, value: any) => this

http.addToBoot function is a shortcut for add data to the "boot" object in http.state

http.addToBoot("authId", 100034);
// is same as
http.state.set("boot.authId", 100034);

Note: Boot data is automatically loaded in all controllers unless boot method exists;

# all()

http.all() returns both query and body data. if there is conflict in key names, the body key will be entertained.

// POST /create-post?name=unknown&category=movies
// body: {name: "Alice in the Borderland"}
// query: {name: "unknown", category: "movies"}

const data = http.all();
console.log(data.name) // Alice in the Borderlan

# body()

# Type: <T=unknown>(key: string, def?: T) => T

http.body function can be used to get a key from the current request body data or return default if not found.

# hasParam()

# Type: (param: string) => boolean

http.hasParam function checks if a name route parameter exists in the current request

// Route: /user/:userId/songs/:songId?

// Get: /user/2/songs
http.hasParam('userId') // true
http.hasParam('songId') // false

// Get: /user/2/songs/18
http.hasParam('songId') // true

// is equivalent to
http.params.hasOwnProperty('songId');

# hasParams()

# Type: (params: string[]) => boolean

Checks if multiple named route parameter exists in the current request

// Route: /user/:userId/songs/:songId?

// Get: /user/2/songs
http.hasParams(['userId', 'songId']) // false

// Get: /user/2/songs/18
http.hasParams(['userId', 'songId']) // true

# json()

# Type: (body: any, status?: number) => Http.Response

Sends a JSON response. This method sends a response (with the correct content-type) that is the parameter converted to a JSON string using JSON.stringify().

The parameter can be any JSON type, including object, array, string, Boolean, number, or null, and you can also use it to convert other values to JSON.

http.json(null)
http.json({user: 'tobi'})
http.json({error: 'message'}, 500)

# next()

# Type: () => void | any

http.next function is used to move to the next request middleware and is only available in middlewares

const kidsOnlyMiddleware = {
  
  allow(http) {
    return http.state.get("age") <= 10 ? // if age <= 10
        http.next() // procced to next request middleware
        : http.send({error: "Your too old"}); // Send error.
  }
}

# query()

# Type: <T=unknown>(key: string, def?: T) => T

http.query function Can be used to get a key from the current request query data or return default if not found.

# redirect()

# Type: (path="/") => any

http.redirect function redirects the current request to another url.

http.redirect() // redirects to `/`

http.redirect("/auth/login") // redirects to `/auth/login`

# redirectBack()

# Type: () => any

http.redirectBack() redirects the current request back to the url it came from. (Referrer)

# redirectToRoute()

# Type: (route: string, params?: any[], query?: object | false, includeUrl?: boolean) => any

http.redirectToRoute function redirects the current request to the route name specified.

  • route: Named route.
  • params: Url parameters array.
  • query: Url query object.
  • includeUrl: if true, your full server url will prefix the route.
$.route.get("/auth/login", "Auth@login").name("login")
$.route.get("/user/:userId/songs/:songId", "Song@mine").name("user.songs")

// Redirect to `/auth/login`
http.redirectToRoute("login");

// Redirect to `/user/2/songs/4`
http.redirectToRoute("user.songs", [2, 4]);

// Redirect to `/user/2/songs/4?draft=true`
http.redirectToRoute("user.songs", [2, 4], {draft: true});

// Redirect to `http://localhost:3000/user/2/songs/4?draft=true`
http.redirectToRoute("user.songs", [2, 4], {draft: true}, true)

# send()

# Type: (body: any, status?: number) => Http.Response

http.send sends the HTTP response. The body parameter can be a Buffer object, a String, an object, Boolean, or an Array. For example:

http.send(Buffer.from('whoop'))
http.send({some: 'json'})
http.send('<p>some html</p>')
http.send('Sorry, we cannot find that!', 404)
http.send({error: 'something blew up'}, 500)

# status()

# Type: (status: number) => this

http.status Sets the HTTP status for the response. It is a chainable alias of Node’s response.statusCode (opens new window)

http.status(400).send('Bad Request') // sets status and sends response

# try()

# Type: <T=unknown>(fn: () => T) => T Xpresser Version: >= 0.6.5

Sometimes when handling request you come across actions that may cause errors, but you know you can proceed without them. http.try gives you the freedom to do stuffs like this using xpresser's InXpresserError class.

http.try(() => {
  // actions to try here
  // logs error but does not stop process.
});

// Also accepts async function.
http.try(async () => {
  // actions to try here
  // logs error but does not stop process.
})

# tryOrCatch()

# Type: <T=unknown>(fn: () => T, handleError?: (error: InXpresserError) => any) => T

Works just like http.try but throws error if not handled. You can handle error by passing a function as the second argument.

http.tryOrCatch(async () => {
  // Try cretaing user
  await User.new(http.$body.all());

}, (e) => {
  return http.send({error: e})
});

# view()

# Type: (file: string, data = {}, fullPath: boolean = false) => any

http.view function Renders a view and sends the rendered HTML string to the client. The view argument is a string that is the file path of the view file to render. This should be relative to the root of your views directory.

If you want to load views outside your view directory, then provide full path to the file and enable the fullPath argument.

/*
-views
-views/auth
-views/auth/login.ejs
-views/auth/signup.ejs
-views/index.ejs
-views/about.ejs
 */

http.view('index') // views/index.ejs
http.view('about') // views/about.ejs
http.view('auth/login') // views/auth/login.ejs
http.view('auth/signup') // views/auth/signup.ejs

# Extend Request Engine

The default RequestEngine can be modified or extended to provide custom functionality for your project/application.

The first step to extending the default RequestEngine is by creating a RequestEngine.(js|ts) file. This file should export your custom RequestEngine class.

Note: new syntax works for xpresser version 0.25.1 and above while old syntax works for any version of xpresser. The new syntax makes it easier for typescript to understand your code.

Next, add the path to your custom RequestEngine (without file extension) to your project's use.json file.

{
  "extends": {
    "RequestEngine": [
      "backend://RequestEngine"
    ]
  }
}

Now you can use the custom badRequest method in your controller like so

// Controller Action
const AppController = {
  
  login(http) {
    return http.badRequest("No username and password found!");
  }

}