@alkocats/http-ts
v0.6.4
Published
A Typescript HTTP server wrapper with express.
Downloads
105
Maintainers
Readme
http-ts
Installation
npm install @alkocats/http-ts
Usage
Example
All relevant imports for a minimal setup:
import { HttpGet, HttpServer, HttpForbiddenError, SimpleRepository, HttpController, HttpResponse, HTTP_STATUS } from '@alkocats/http-ts';
The user interface for the user repository:
interface User {
name: string;
password: string;
}
The user repository for the stored data the controller uses:
class UserRepository extends SimpleRepository<User[]> {
public async getAsyncData(): Promise<User[]> {
return this.data;
}
public async addUser(name: string, password: string): Promise<void> {
this.data.push({
name: name,
password: password
});
}
}
The user controller, which handles the user requests, equipped with different GET-methods:
class UserController extends HttpController<UserRepository> {
/**
* Define a GET-method for the url /users.
*/
@HttpGet('/users')
public getUsers(): User[] {
return this.repository.getData();
}
/**
* Define a asynchronous GET-method for the url /async-users.
*/
@HttpGet('/async-users')
public async getAsyncUsers(): Promise<User[]> {
return await this.repository.getAsyncData();
}
/**
* Define a asynchronous GET-method for the url /async-users-with-http-response and a custom http code
*/
@HttpGet('/async-users-with-http-response')
public async getAsyncUsersWithHttpResponse(): Promise<HttpResponse> {
const data = await this.repository.getAsyncData();
return new HttpResponse(data, HTTP_STATUS.CODE_202_ACCEPTED);
}
/**
* Define a asynchronous POST-method for the url /async-post-data which handles JSON bodies
*/
@HttpPost('/post-data/:username')
public async postAsyncData(options: HttpRequestOptions): Promise<User[]> {
const name = options.request.params.username;
const password = options.request.body.password;
this.repository.addUser(name, password);
return this.repository.getAsyncData();
}
/**
* Define a GET-method for the url /faulty-users which throws a HTTP error.
* None HTTP errors are automatically transformed to HTTP 500 error.
*/
@HttpGet('/faulty-method')
public faultyMethod(): HttpResponse {
throw new HttpForbiddenError();
}
}
Bringing it all together:
const userRepository = new UserRepository([{
name: 'admin',
password: 'the-cake-is-a-lie'
}]);
const userController = new UserController(userRepository);
const httpServer = new HttpServer();
httpServer.registerController(userController);
httpServer.start();
Basic JWT / bcrypt Authentication
All relevant imports for a minimal setup:
import * as bcrypt from 'bcrypt';
import { Authenticated, HttpController, HttpGet, HttpServer, JwtAuthenticator, SimpleRepository } from '@alkocats/http-ts';
The user interface for the user repository:
interface User {
email: string;
password: string;
}
The data interface for the data repository:
interface Data {
foo: number;
bar: string;
}
The data repository for the stored data the controller uses:
class DataRepository extends SimpleRepository<Data[]> {
public getSecretData(): Data[] {
return [{
foo: 0,
bar: 'top secret'
}];
}
}
const dataRepository = new DataRepository([{
foo: 1,
bar: 'no secret data'
}]);
The data controller, which handles all data requests.
class DataController extends HttpController<DataRepository> {
/**
* A unauthaenticated get method which can be called by everyone
*/
@HttpGet('/data')
public getDataUnauthenticated() {
return this.repository.getData();
}
/**
* An authenticated get method, which can only be called by authenticated
* users who deliver a valid bearer token.
*/
@Authenticated()
@HttpGet('/data-authenticated')
public getDataAuthenticated(): Data[] {
return this.repository.getSecretData();
}
}
const dataController = new DataController(dataRepository);
Bringing it all together:
async function main() {
// To login with a valid password, the password needs to be hashed with bcrypt
const hashedPassword = await bcrypt.hash('the-cake-is-a-lie', 10);
// This repository is used by the JwtAuthenticator and contains all valid logins.
const userRepository = new SimpleRepository<User[]>([{
email: '[email protected]',
password: hashedPassword
}]);
// The secret for JwtAuthenticator to use for encryption / decryption.
const secret = 'some-secret';
/**
* The path '/auth' defines, where to make a post with email / password
* as a json object to obtain a valid bearer token.
* The token then can be used to access @Authenticated methods of the
* registered controllers.
*/
const authenticator = new JwtAuthenticator<User>('/auth', {
// Defines the repository with all the valid logins
repository: userRepository,
// Defines, which field of the repository data is used for identification
identificationKey: 'email',
// Defines, in which field of the repository data the hashed password is stored
passwordKey: 'password',
// Defines the expiration time of generated tokens (still valid after restart of server)
expiresIn: 86400,
// Defines the secret JWT uses to encrypt / decrypt the generated tokens.
secret: secret
});
const httpServer = new HttpServer(80, authenticator);
httpServer.registerController(dataController);
httpServer.start();
}
main();
After everything is implemented, a POST to http://localhost/auth with the JSON data
{
"email": "[email protected]",
"password": "the-cake-is-a-lie"
}
generates a bearer token, wich can be used in future requests to access @Authenticated methods of the registered controllers.
Alternatively a custom Authenticater can be created by creating a class which extends Authenticator.
API
Supported HTTP Methods
@HttpGet(path: string)
@HttpPut(path: string)
@HttpPost(path: string)
@HttpDelete(path: string)
@HttpPatch(path: string)
@HttpHead(path: string)
@HttpTrace(path: string)
@HttpConnect(path: string)
Contributing
Feel free to create branches or pull requests.