Upgrading to v1
v1
contains major and breaking changes.
But don't worry! You can upgrade your project easily by using this documentation.
Overview
The major changes are the following;
- Express.js has been removed. Axe API uses the http module instead. It has improved its performance by around 40%.
- A new logger library, pino, has been added.
- Internal rate limiting has been added.
- Form uploading helpers have been added.
- Swagger support
- Auto-caching (via Redis)
- Full-text search (via Elasticsearch)
You can apply the following steps in your project.
Step 1. Update the new version
Update the axe-api
version in your package.json
file:
"dependencies": {
"axe-api": "^1.0.0"
}
$ npm install
Step 2. Add pino configurations
You should update your pino
configuration in the app/config.ts
file:
import { IApplicationConfig } from "axe-api";
const config: IApplicationConfig = {
// ...
pino: {
level: "debug",
transport: {
target: "pino-pretty",
},
},
// ...
};
TIP
You can learn more from the pino documentation.
Step 3. Add caching configuration
Axe API has started to provide an auto-caching mechanism with the new version.
You can set up your caching configurations like the following example;
import { RedisClientOptions } from "redis";
import { IApplicationConfig, CacheStrategies } from "axe-api";
const config: IApplicationConfig = {
// ...
redis: RedisClientOptions,
cache: {
enable: true,
ttl: 300,
invalidation: CacheStrategies.TimeBased,
},
// ...
};
Step 4. LogLevels
is removed
The LogLevels
configuration is removed because Axe API started to support pino. as the logger.
import { IApplicationConfig, LogLevels } from "axe-api";
import { IApplicationConfig } from "axe-api";
const config: IApplicationConfig = {
// ...
logLevel: LogLevels.INFO,
// ...
};
Step 5. Set up the error handler
Axe API allows you to add a general error handler function for your API. You can set the error handler function via the app/config.ts
file.
import { IApplicationConfig } from "axe-api";
import errorHandler from "./errorHandler";
const config: IApplicationConfig = {
// ...
errorHandler,
// ...
};
import { IncomingMessage, ServerResponse } from "http";
import { NextFunction } from "axe-api/build/src/Types";
export default function (
err: any,
req: IncomingMessage,
res: ServerResponse,
next: NextFunction,
) {
if (process.env.NODE_ENV === "production") {
// Send errors to your error monitoring tool like Sentry
}
// Sett the HTTP status code
res.statusCode = 500;
// Set the default HTTP message
res.write(
JSON.stringify({
error: "Internal server error",
message: err.message,
}),
);
res.end();
next();
}
Step 6. Set up the rate-limiter
Since Axe API is a specified framework for building APIs, it now supports a rate-limiter internally. You can enable the rate-limiter via the app/config.ts
file.
import { IApplicationConfig } from "axe-api";
const config: IApplicationConfig = {
// ...
rateLimit: {
enabled: false,
maxRequests: 240,
windowInSeconds: 60,
trustProxyIP: true,
adaptor: "redis",
},
// ...
};
Step 7. Set up documentations
You can enable or disable the auto-created documentation via the configuration file.
import { IApplicationConfig } from "axe-api";
const config: IApplicationConfig = {
// ...
docs: true,
// ...
};
Your API documentation will be automatically generated with Swagger. You can define the base structure of the documentation by editing the following file by yourself. The swagger.ts
file would be the base of the documentation, and Axe API would override it.
export default {
info: {
title: "Your API Title",
description: "Description the API in here",
},
servers: [
{
url: "https://your-api.com",
},
],
};
TIP
You can get more information via Swagger help files.
Step 8. IRequestPack change
The IRequestPack
interface has been renamed as IContext
.
import { IRequestPack } from "axe-api";
import { IContext } from "axe-api";
// export default async (params: IRequestPack) => {
// [!code ++] export default async (params: IContext) => {
// your hook/event function
};
Step 9. Express req
and res
Axe API doesn't support Express.js any more. So you can not use req
and res
objects of Express.js. Instead, you can use AxeRequest
and AxeResponse
in your APIs.
import { Request, Response } from "express";
import { AxeRequest, AxeResponse } from "axe-api";
// [!code --] export default async (req: Request, res: Response) => {
// [!code ++] export default async (req: AxeRequest, res: AxeResponse) => {
}
Step 10. IoCService changes
The IoCService.useByType()
method has been removed. You can use the use<T>()
method instead.
IoCService.useByType<Knex>("Database");
IoCService.use<Knex>("Database");
Step 11. Middlewares
You should use connect middleware functions instead of Express.js middleware.
import { Request, Response, NextFunction } from "express";
import { IncomingMessage, ServerResponse, NextFunction } from "http";
export const myMiddleware = (
req: Request,
req: IncomingMessage,
res: Response,
res: ServerResponse,
next: NextFunction,
): void => {
next();
};
WARNING
You should use connect-based middleware functions instead of Express.js middleware.
We had to make this decision to get rid of Express.js. Please let us know if there is an Express.js middleware that doesn't have a connect version.
We can figure it out together! 💪
Step 12. Init functions
Axe API started to use its own App
instance instead of Express.js' app instance.
You should use the Axe API App instance in your app/{version}/init.ts
files like the following example;
import { Express } from "express";
import { App } from "axe-api";
// [!code --] const onBeforeInit = async (app: Express) => {
// [!code ++] const onBeforeInit = async (app: App) => {
// your logic
};
// [!code --] const onAfterInit = async (app: Express) => {
// [!code ++] const onAfterInit = async (app: App) => {
// your logic
};
export { onBeforeInit, onAfterInit };
Step 13. IMethodBaseConfig
The IMethodBaseValidations
interface has been renamed with IMethodBaseConfig
.
import { Model, IMethodBaseValidations } from "axe-api"
import { Model, IMethodBaseConfig } from "axe-api"
class User extends Model {
get fillable() IMethodBaseValidations {
get fillable() IMethodBaseConfig<string[]> {
return {
"POST": ["name", "surname"]
}
}
}
Step 14. IHandlerBasedTransactionConfig
The definition of the IHandlerBasedTransactionConfig
interface has been changed. You should change your model transaction configurations to the new type.
export interface IHandlerBasedTransactionConfig {
handler: HandlerTypes | HandlerTypes[];
handlers: HandlerTypes[];
transaction: boolean;
}
Step 15. LogService method changes
Axe API started to use the pino library as the logger. It doesn't support success()
or log()
methods anymore.
You can use debug()
method instead.
LogService.success("My success message");
LogService.log("My log message");
LogService.debug("My success or log message");
Step 16. Model types
The Axe API model has new return types.
You should review the following changes and apply them to your models;
validations()
class Model {
// [!code --] get validations(): ModelValidation | IMethodBaseValidations {}
// [!code ++] get validations(): ModelValidation | IMethodBaseConfig<ModelValidation> {}
}
export interface IMethodBaseConfig<T> {
[HttpMethods.POST]?: T;
[HttpMethods.PUT]?: T;
[HttpMethods.PATCH]?: T;
}
middlewares()
class Model {
// [!code --] get middlewares():
// [!code --] | MiddlewareFunction[]
// [!code --] | IHandlerBaseMiddleware[]
// [!code --] | IHandlerBaseMiddleware {}
// [!code ++] get middlewares(): ModelMiddleware {}
}
type ModelMiddleware = Array<AxeFunction | IHandlerBaseMiddleware>;
type AxeFunction = GeneralFunction | PhaseFunction;
type GeneralFunction = MiddlewareFunction | HandlerFunction;
type PhaseFunction = (context: IContext) => DefaultResponse;
export type MiddlewareFunction = (
req: IncomingMessage,
res: ServerResponse,
next: NextFunction,
) => DefaultResponse;
export type HandlerFunction = (
request: AxeRequest,
response: AxeResponse,
) => DefaultResponse;
export interface IHandlerBaseMiddleware {
handler: HandlerTypes[];
middleware: AxeFunction;
}
transaction()
class Model {
// [!code --] get transaction():
// [!code --] | boolean
// [!code --] | IHandlerBasedTransactionConfig
// [!code --] | IHandlerBasedTransactionConfig[]
// [!code --] | null {}
// [!code ++] get transaction(): boolean | IHandlerBasedTransactionConfig[] {}
}
export interface IHandlerBasedTransactionConfig {
handlers: HandlerTypes[];
transaction: boolean;
}
Next steps
We tried to cover all major changes in this documentation. On the other hand, there are many new features. You can review the documentation and implement new features in your APIs.
Please let us know if you notice anything broken so we can fix it quickly.
Let's develop better APIs together with the power of Axe API! 💪