UNPKG

typescript-rest

Version:
811 lines (791 loc) 40.4 kB
<!doctype html> <html class="default no-js"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>Typescript-rest</title> <meta name="description" content=""> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="assets/css/main.css"> <script src="assets/js/modernizr.js"></script> </head> <body> <header> <div class="tsd-page-toolbar"> <div class="container"> <div class="table-wrap"> <div class="table-cell" id="tsd-search" data-index="assets/js/search.js" data-base="."> <div class="field"> <label for="tsd-search-field" class="tsd-widget search no-caption">Search</label> <input id="tsd-search-field" type="text" /> </div> <ul class="results"> <li class="state loading">Preparing search index...</li> <li class="state failure">The search index is not available</li> </ul> <a href="index.html" class="title">Typescript-rest</a> </div> <div class="table-cell" id="tsd-widgets"> <div id="tsd-filter"> <a href="#" class="tsd-widget options no-caption" data-toggle="options">Options</a> <div class="tsd-filter-group"> <div class="tsd-select" id="tsd-filter-visibility"> <span class="tsd-select-label">All</span> <ul class="tsd-select-list"> <li data-value="public">Public</li> <li data-value="protected">Public/Protected</li> <li data-value="private" class="selected">All</li> </ul> </div> <input type="checkbox" id="tsd-filter-inherited" checked /> <label class="tsd-widget" for="tsd-filter-inherited">Inherited</label> <input type="checkbox" id="tsd-filter-only-exported" /> <label class="tsd-widget" for="tsd-filter-only-exported">Only exported</label> </div> </div> <a href="#" class="tsd-widget menu no-caption" data-toggle="menu">Menu</a> </div> </div> </div> </div> <div class="tsd-page-title"> <div class="container"> <ul class="tsd-breadcrumb"> <li> <a href="globals.html">Globals</a> </li> </ul> <h1> Typescript-rest</h1> </div> </div> </header> <div class="container container-main"> <div class="row"> <div class="col-8 col-content"> <div class="tsd-panel tsd-typography"> <h1 id="rest-services-for-typescript">REST Services for Typescript</h1> <p>This is a lightweight annotation-based <a href="http://expressjs.com/">expressjs</a> extension for typescript.</p> <p>It can be used to define your APIs using ES7 decorators.</p> <p><strong>Table of Contents</strong> </p> <ul> <li><a href="#">REST Services for Typescript</a><ul> <li><a href="#installation">Installation</a></li> <li><a href="#configuration">Configuration</a></li> <li><a href="#basic-usage">Basic Usage</a></li> <li><a href="#complete-guide">Complete Guide</a><ul> <li><a href="#server">Server</a></li> <li><a href="#path-decorator">@Path Decorator</a><ul> <li><a href="#path-parameters">Path Parameters</a></li> </ul> </li> <li><a href="#http-methods">Http Methods</a></li> <li><a href="#parameters">Parameters</a></li> <li><a href="#service-context">Service Context</a></li> <li><a href="#service-return">Service Return</a><ul> <li><a href="#asynchronous-services">Asynchronous services</a></li> </ul> </li> <li><a href="#errors">Errors</a></li> <li><a href="#types-and-languages">Types and languages</a></li> </ul> </li> </ul> </li> </ul> <h2 id="installation">Installation</h2> <p>This library only works with typescript. Ensure it is installed:</p> <pre><code class="lang-bash">npm install typescript -g </code></pre> <p>To install typescript-rest:</p> <pre><code class="lang-bash">npm install typescript-rest --save </code></pre> <h2 id="configuration">Configuration</h2> <p>Typescript-rest requires the following TypeScript compilation options in your tsconfig.json file:</p> <pre><code class="lang-typescript">{ <span class="hljs-string">"compilerOptions"</span>: { <span class="hljs-string">"experimentalDecorators"</span>: <span class="hljs-literal">true</span>, <span class="hljs-string">"emitDecoratorMetadata"</span>: <span class="hljs-literal">true</span> } } </code></pre> <h2 id="basic-usage">Basic Usage</h2> <pre><code class="lang-typescript"><span class="hljs-keyword">import</span> * as express from <span class="hljs-string">"express"</span>; <span class="hljs-keyword">import</span> {Server, Path, GET, PathParam} from <span class="hljs-string">"typescript-rest"</span>; @Path(<span class="hljs-string">"/hello"</span>) <span class="hljs-keyword">class</span> HelloService { @Path(<span class="hljs-string">":name"</span>) @GET sayHello( @PathParam(<span class="hljs-string">'name'</span>) name: <span class="hljs-built_in">string</span>): <span class="hljs-built_in">string</span> { <span class="hljs-keyword">return</span> <span class="hljs-string">"Hello "</span> + name; } } <span class="hljs-keyword">let</span> app: express.Application = express(); Server.buildServices(app); app.listen(<span class="hljs-number">3000</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Rest Server listening on port 3000!'</span>); }); </code></pre> <p>That&#39;s it. You can just call now:</p> <pre><code>GET http:<span class="hljs-regexp">//</span>localhost:<span class="hljs-number">3000</span><span class="hljs-regexp">/hello/</span>joe </code></pre><h2 id="complete-guide">Complete Guide</h2> <p>This library allows you to use ES7 decorators to configure your services using expressjs. </p> <h3 id="server">Server</h3> <p>The Server class is used to configure the server, like: </p> <pre><code class="lang-typescript"><span class="hljs-keyword">let</span> app: express.Application = express(); Server.setFileDest(<span class="hljs-string">'/uploads'</span>); Server.buildServices(app); app.listen(<span class="hljs-number">3000</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{ <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Rest Server listening on port 3000!'</span>); }); </code></pre> <p>Note that Server receives an <code>express.Router</code> instance. Then it configures all the routes based on the decorators used on your classes.</p> <p>So, you can use also any other expressjs feature, like error handlers, middlewares etc without any restriction. </p> <h3 id="-path-decorator">@Path Decorator</h3> <p>The @Path decorator allow us to define a router path for a given endpoint. Route paths, in combination with a request method, define the endpoints at which requests can be made. Route paths can be strings, string patterns, or regular expressions.</p> <p>The characters ?, +, *, and () are subsets of their regular expression counterparts. The hyphen (-) and the dot (.) are interpreted literally by string-based paths.</p> <p><em>We use <a href="https://www.npmjs.com/package/path-to-regexp">path-to-regexp</a> for matching the route paths; see the path-to-regexp documentation for all the possibilities in defining route paths.</em></p> <p>Some examples:</p> <pre><code class="lang-typescript">@Path(<span class="hljs-string">"/hello"</span>) <span class="hljs-keyword">class</span> HelloService { } </code></pre> <pre><code class="lang-typescript">@Path(<span class="hljs-string">"/test/hello"</span>) <span class="hljs-keyword">class</span> TestService { } </code></pre> <p>This route path will match acd and abcd:</p> <pre><code class="lang-typescript">@Path(<span class="hljs-string">"ab?cd"</span>) <span class="hljs-keyword">class</span> TestService { } </code></pre> <p>This route path will match abcd, abbcd, abbbcd, and so on:</p> <pre><code class="lang-typescript">@Path(<span class="hljs-string">"ab+cd"</span>) <span class="hljs-keyword">class</span> TestService { } </code></pre> <p>This route path will match abcd, abxcd, abRANDOMcd, ab123cd, and so on:</p> <pre><code class="lang-typescript">@Path(<span class="hljs-string">"ab*cd"</span>) <span class="hljs-keyword">class</span> TestService { } </code></pre> <p>This route path will match /abe and /abcde:</p> <pre><code class="lang-typescript">@Path(<span class="hljs-string">"/ab(cd)?e"</span>) <span class="hljs-keyword">class</span> TestService { } </code></pre> <p>This route path will match butterfly and dragonfly, but not butterflyman, dragonfly man, and so on:</p> <pre><code class="lang-typescript">@Path(<span class="hljs-string">"/.*fly$/"</span>) <span class="hljs-keyword">class</span> TestService { } </code></pre> <h4 id="path-parameters">Path Parameters</h4> <p>Route parameters are named URL segments that are used to capture the values specified at their position in the URL. The captured values are populated in the req.params object, with the name of the route parameter specified in the path as their respective keys. They can be refered through @PathParam decorator on a service method argument.</p> <p>Some examples:</p> <pre><code class="lang-typescript">@Path(<span class="hljs-string">"/users"</span>) <span class="hljs-keyword">class</span> UserService { @Path(<span class="hljs-string">"/:userId/books/:bookId"</span>) @GET getUserBook(@PathParam(<span class="hljs-string">"userId"</span>) userId: <span class="hljs-built_in">number</span>, @PathParam(<span class="hljs-string">"bookId"</span>) bookId: <span class="hljs-built_in">number</span>): Promise&lt;Book&gt; { <span class="hljs-comment">//...</span> } } </code></pre> <p>The requested URL <a href="http://localhost:3000/users/34/books/8989">http://localhost:3000/users/34/books/8989</a> would map the parameters as:</p> <pre><code><span class="hljs-symbol"> userId:</span> <span class="hljs-string">"34"</span> <span class="hljs-symbol"> bookId:</span> <span class="hljs-string">"8989"</span> </code></pre><p>Since the hyphen (-) and the dot (.) are interpreted literally, they can be used along with route parameters for useful purposes.</p> <pre><code>Route <span class="hljs-string">path:</span> <span class="hljs-regexp">/flights/</span>:from-:to Request <span class="hljs-string">URL:</span> <span class="hljs-string">http:</span><span class="hljs-comment">//localhost:3000/flights/LAX-SFO</span> req.<span class="hljs-string">params:</span> { <span class="hljs-string">"from"</span>: <span class="hljs-string">"LAX"</span>, <span class="hljs-string">"to"</span>: <span class="hljs-string">"SFO"</span> } </code></pre><pre><code>Route <span class="hljs-string">path:</span> <span class="hljs-regexp">/plantae/</span>:genus.:species Request <span class="hljs-string">URL:</span> <span class="hljs-string">http:</span><span class="hljs-comment">//localhost:3000/plantae/Prunus.persica</span> req.<span class="hljs-string">params:</span> { <span class="hljs-string">"genus"</span>: <span class="hljs-string">"Prunus"</span>, <span class="hljs-string">"species"</span>: <span class="hljs-string">"persica"</span> } </code></pre><h3 id="http-methods">Http Methods</h3> <p>We have decorators for each HTTP method. Theses decorators are used on service methods already bound to a Path route to specify the endpoint at which requests can be made.</p> <p>The following decorators can be used:</p> <ul> <li>@GET </li> <li>@POST</li> <li>@PUT</li> <li>@PATCH</li> <li>@DELETE</li> <li>@OPTIONS</li> <li>@HEAD</li> </ul> <p>Some examples:</p> <pre><code class="lang-typescript">@Path(<span class="hljs-string">"/users"</span>) <span class="hljs-keyword">class</span> UserService { @GET getUsers(): Promise&lt;<span class="hljs-built_in">Array</span>&lt;User&gt;&gt; { <span class="hljs-comment">//...</span> } @GET @Path(<span class="hljs-string">":userId"</span>) getUser(@PathParam(<span class="hljs-string">"userId"</span>)): Promise&lt;User&gt; { <span class="hljs-comment">//...</span> } @PUT @Path(<span class="hljs-string">":userId"</span>) saveUser(@PathParam(<span class="hljs-string">"userId"</span>), user: User): <span class="hljs-built_in">void</span> { <span class="hljs-comment">//...</span> } } </code></pre> <p>Only methods decorated with one of this HTTP method decorators are exposed as handlers for requests on the server.</p> <p>A single method can only be decorated with one of those decorators at a time.</p> <h3 id="parameters">Parameters</h3> <p>There are decorators to map parameters to arguments on service methods. Each decorator can map a differente kind of parameter on request.</p> <p>The following decorators are available:</p> <table> <thead> <tr> <th>Decorator</th> <th>Description</th> </tr> </thead> <tbody> <tr> <td>@PathParam</td> <td>Parameter in requested URL path </td> </tr> <tr> <td>@QueryParam</td> <td>Parameter in the query string </td> </tr> <tr> <td>@FormParam</td> <td>Parameter in an HTML form </td> </tr> <tr> <td>@HeaderParam</td> <td>Parameter in the request header</td> </tr> <tr> <td>@CookieParam</td> <td>Parameter in a cookie </td> </tr> <tr> <td>@FileParam</td> <td>A File in a multipart form </td> </tr> <tr> <td>@FilesParam</td> <td>An array of Files in a multipart form </td> </tr> <tr> <td>@Param</td> <td>Parameter in the query string or in an HTML form</td> </tr> </tbody> </table> <p>Some examples:</p> <pre><code class="lang-typescript">@Path(<span class="hljs-string">"/sample"</span>) <span class="hljs-keyword">class</span> Sample { @GET test(@QueryParam(<span class="hljs-string">"limit"</span>) limit:<span class="hljs-built_in">number</span>, @QueryParam(<span class="hljs-string">"skip"</span>) skip:<span class="hljs-built_in">number</span>) { <span class="hljs-comment">//...</span> <span class="hljs-comment">// GET http://domain/sample?limit=5&amp;skip=10</span> } @POST test(@FormParam(<span class="hljs-string">"name"</span>) name:<span class="hljs-built_in">string</span>) { <span class="hljs-comment">//...</span> <span class="hljs-comment">// POST http://domain/sample</span> <span class="hljs-comment">// body: name=joe</span> } @POST @Path(<span class="hljs-string">"upload"</span>) testUploadFile( @FileParam(<span class="hljs-string">"myFile"</span>) file: Express.Multer.File, @FormParam(<span class="hljs-string">"myField"</span>) myField: <span class="hljs-built_in">string</span>) { <span class="hljs-comment">//...</span> <span class="hljs-comment">/* POST http://domain/sample/upload Content-Type: multipart/form-data; boundary=AaB03x --AaB03x Content-Disposition: form-data; name="myField" Field Value --AaB03x Content-Disposition: form-data; name="myFile"; filename="file1.txt" Content-Type: text/plain ... contents of file1.txt ... --AaB03x-- */</span> } } </code></pre> <p>An argument that has no decorator is handled as a json serialized entity in the request body </p> <pre><code class="lang-typescript">@Path(<span class="hljs-string">"/sample"</span>) <span class="hljs-keyword">class</span> Sample { @POST test(user: User) { <span class="hljs-comment">//...</span> <span class="hljs-comment">// POST http://domain/sample</span> <span class="hljs-comment">// body: a json representation of the User object</span> } } </code></pre> <h3 id="service-context">Service Context</h3> <p>A Context object is created to group informations about the current request being handled. This Context can be accessed by service methods.</p> <p>The Context is represented by the <code>ServiceContext</code> class and has the following properties:</p> <table> <thead> <tr> <th>Property</th> <th>Type</th> <th>Description</th> </tr> </thead> <tbody> <tr> <td>request</td> <td>express.Request</td> <td>The request object </td> </tr> <tr> <td>response</td> <td>express.Response</td> <td>The response object </td> </tr> <tr> <td>language</td> <td>string</td> <td>The resolved language to be used to handle the current request. </td> </tr> <tr> <td>accept</td> <td>string</td> <td>The preferred media type to be used to respond the current request. </td> </tr> <tr> <td>next</td> <td>express.NextFunction</td> <td>The next function. It can be used to delegate to the next middleware registered the processing of the current request. </td> </tr> </tbody> </table> <p>See <a href="#types-and-languages">Types and languages</a> to know how the language and preferredMedia fields are calculated.</p> <p>The <code>@Context</code> decorator can be used on service method&#39;s arguments or on service class properties to bind the argument or the property to the current context object. </p> <p>A Context usage example:</p> <pre><code class="lang-typescript"> @Path(<span class="hljs-string">"context"</span>) <span class="hljs-keyword">class</span> TestService { @Context context: ServiceContext; @GET sayHello() { <span class="hljs-keyword">switch</span> (<span class="hljs-keyword">this</span>.context.language) { <span class="hljs-keyword">case</span> <span class="hljs-string">"en"</span>: <span class="hljs-keyword">return</span> <span class="hljs-string">"Hello"</span>; <span class="hljs-keyword">case</span> <span class="hljs-string">"pt"</span>: <span class="hljs-keyword">return</span> <span class="hljs-string">"Olá"</span>; } <span class="hljs-keyword">return</span> <span class="hljs-string">"Hello"</span>; } } </code></pre> <p>We can use the decorator on method arguments too:</p> <pre><code class="lang-typescript"> @Path(<span class="hljs-string">"context"</span>) <span class="hljs-keyword">class</span> TestService { @GET sayHello(@Context context: ServiceContext) { <span class="hljs-keyword">switch</span> (context.language) { <span class="hljs-keyword">case</span> <span class="hljs-string">"en"</span>: <span class="hljs-keyword">return</span> <span class="hljs-string">"Hello"</span>; <span class="hljs-keyword">case</span> <span class="hljs-string">"pt"</span>: <span class="hljs-keyword">return</span> <span class="hljs-string">"Olá"</span>; } <span class="hljs-keyword">return</span> <span class="hljs-string">"Hello"</span>; } } </code></pre> <p>You can use, also, one of the other decorators to access directly one of the Context property. It is a kind of suggar syntax.</p> <ul> <li>@ContextRequest: To access ServiceContext.request</li> <li>@ContextResponse: To access ServiceContext.response</li> <li>@ContextNext: To access ServiceContext.next</li> <li>@ContextLanguage: To access ServiceContext.language</li> <li>@ContextAccept: To access ServiceContext.accept</li> </ul> <pre><code class="lang-typescript"> @Path(<span class="hljs-string">"context"</span>) <span class="hljs-keyword">class</span> TestService { @GET sayHello(@ContextLanguage language: <span class="hljs-built_in">string</span>) { <span class="hljs-keyword">switch</span> (language) { <span class="hljs-keyword">case</span> <span class="hljs-string">"en"</span>: <span class="hljs-keyword">return</span> <span class="hljs-string">"Hello"</span>; <span class="hljs-keyword">case</span> <span class="hljs-string">"pt"</span>: <span class="hljs-keyword">return</span> <span class="hljs-string">"Olá"</span>; } <span class="hljs-keyword">return</span> <span class="hljs-string">"Hello"</span>; } } </code></pre> <h3 id="service-return">Service Return</h3> <p>This library can receive the return of your service method and handle the serialization of the response as long as handle the correct content type of your result and the response status codes to be sent.</p> <p>When a primitive type is returned by a service method, it is sent as a plain text into the response body.</p> <pre><code class="lang-typescript">@GET sayHello(): <span class="hljs-built_in">string</span> { <span class="hljs-keyword">return</span> <span class="hljs-string">"Hello"</span>; } </code></pre> <p>The response will contains only the String <code>Hello</code> as a plain text </p> <p>When an object is returned, it is sent as a json serialized string into the response body.</p> <pre><code class="lang-typescript">@GET @Path(<span class="hljs-string">":id"</span>) getPerson(@PathParam(<span class="hljs-string">":id"</span>) id: <span class="hljs-built_in">number</span>): Person { <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Person(id); } </code></pre> <p>The response will contains the person json serialization (ex: <code>{id: 123}</code>. The response will have a <code>application/json</code> context type. </p> <p>When the method returns nothing, an empty body is sent withh a <code>204</code> status code.</p> <pre><code class="lang-typescript">@POST test(myObject: MyClass): <span class="hljs-built_in">void</span> { <span class="hljs-comment">//...</span> } </code></pre> <p>We provide also, some special types to inform that a reference to a resource is returned and that the server should handle it properly.</p> <table> <thead> <tr> <th>Type</th> <th>Description</th> </tr> </thead> <tbody> <tr> <td>NewResource</td> <td>Inform that a new resource was created. Server will add a Location header and set status to 201 </td> </tr> <tr> <td>RequestAccepted</td> <td>Inform that the request was accepted but is not completed. A Location header should inform the location where the user can monitor his request processing status. Server will set the status to 202 </td> </tr> <tr> <td>MovedPermanently</td> <td>Inform that the resource has permanently moved to a new location, and that future references should use a new URI with their requests. Server will set the status to 301 </td> </tr> <tr> <td>MovedTemporarily</td> <td>Inform that the resource has temporarily moved to another location, but that future references should still use the original URI to access the resource. Server will set the status to 302 </td> </tr> </tbody> </table> <pre><code class="lang-typescript"><span class="hljs-keyword">import</span> {Return} from <span class="hljs-string">"typescript-rest"</span>; @Path(<span class="hljs-string">"test"</span>) <span class="hljs-keyword">class</span> TestService { @POST test(myObject: MyClass, @ContextRequest request: express.Request): Return.NewResource { <span class="hljs-comment">//...</span> <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Return.NewResource(req.url + <span class="hljs-string">"/"</span> + generatedId); } } </code></pre> <p>The server will return an empty body with a <code>201</code> status code and a <code>Location</code> header pointing to the URL of the created resource. </p> <h4 id="asynchronous-services">Asynchronous services</h4> <p>The above section shows how the types returned are handled by the Server. However, all the previous examples are working synchronously. The recommended way is to work asynchronously, for a better performance.</p> <p>To work asynchronously, you can return a <code>Promise</code> on your service method. The above rules to handle return types applies to the returned promise resolved value.</p> <p>Some examples:</p> <pre><code class="lang-typescript"><span class="hljs-keyword">import</span> {Return} from <span class="hljs-string">"typescript-rest"</span>; @Path(<span class="hljs-string">"async"</span>) <span class="hljs-keyword">class</span> TestService { @POST test(myObject: MyClass, @ContextRequest request: express.Request): Promise&lt;Return.NewResource&gt; { <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Promise&lt;Return.NewResource&gt;(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">resolve, reject</span>)</span>{ <span class="hljs-comment">//...</span> resolve(<span class="hljs-keyword">new</span> Return.NewResource(req.url + <span class="hljs-string">"/"</span> + generatedId)); }); } @GET testGet() { <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Promise&lt;MyClass&gt;(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">resolve, reject</span>)</span>{ <span class="hljs-comment">//...</span> resolve(<span class="hljs-keyword">new</span> MyClass()); }); } } </code></pre> <p>It is important to observe that you can inform your return type explicitly or not, as you can see in the above example. </p> <h3 id="errors">Errors</h3> <p>This library provide some Error classes to map the problems that you may want to report to your clients.</p> <table> <thead> <tr> <th>Type</th> <th>Description</th> </tr> </thead> <tbody> <tr> <td>BadRequestError</td> <td>Used to report errors with status code 400. </td> </tr> <tr> <td>UnauthorizedError</td> <td>Used to report errors with status code 401. </td> </tr> <tr> <td>ForbidenError</td> <td>Used to report errors with status code 403. </td> </tr> <tr> <td>NotFoundError</td> <td>Used to report errors with status code 404. </td> </tr> <tr> <td>MethodNotAllowedError</td> <td>Used to report errors with status code 405. </td> </tr> <tr> <td>NotAcceptableError</td> <td>Used to report errors with status code 406. </td> </tr> <tr> <td>ConflictError</td> <td>Used to report errors with status code 409. </td> </tr> <tr> <td>InternalServerError</td> <td>Used to report errors with status code 500. </td> </tr> <tr> <td>NotImplementedError</td> <td>Used to report errors with status code 501. </td> </tr> </tbody> </table> <p>If you throw any of these errors on a service method, the server you log the problem and send a response with the appropriate status code an the error message on its body.</p> <pre><code class="lang-typescript"><span class="hljs-keyword">import</span> {Errors} from <span class="hljs-string">"typescript-rest"</span>; @Path(<span class="hljs-string">"async"</span>) <span class="hljs-keyword">class</span> TestService { @GET @Path(<span class="hljs-string">"test1"</span>) testGet() { <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Promise&lt;MyClass&gt;(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">resolve, reject</span>)</span>{ <span class="hljs-comment">//...</span> <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Errors.NotImplementedError(<span class="hljs-string">"This operation is not available yet"</span>); }); } @GET @Path(<span class="hljs-string">"test2"</span>) testGet2() { <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Promise&lt;MyClass&gt;(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">resolve, reject</span>)</span>{ <span class="hljs-comment">//...</span> reject(<span class="hljs-keyword">new</span> Errors.NotImplementedError(<span class="hljs-string">"This operation is not available yet"</span>)); }); } @GET @Path(<span class="hljs-string">"test3"</span>) testGet3() { <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Errors.NotImplementedError(<span class="hljs-string">"This operation is not available yet"</span>); } } </code></pre> <p>All the three operations above will return a response with status code <code>501</code> and a message on the body <code>This operation is not available yet</code></p> <p>If you want to create a custom error that report your own status code, just extend the base class <code>HttpError</code>.</p> <pre><code class="lang-typescript"><span class="hljs-keyword">import</span> {HttpError} from <span class="hljs-string">"typescript-rest"</span>; <span class="hljs-keyword">class</span> MyOwnError extends HttpError { <span class="hljs-keyword">static</span> myNoSenseStatusCode: <span class="hljs-built_in">number</span> = <span class="hljs-number">999</span>; <span class="hljs-keyword">constructor</span>(message?: string) { <span class="hljs-keyword">super</span>(<span class="hljs-string">"MyOwnError"</span>, MyOwnError.myNoSenseStatusCode, message); } } </code></pre> <h3 id="types-and-languages">Types and languages</h3> <p>It is possible to use decorators to inform the server which languages or mime types are supported by each service method.</p> <p>These decorators can be used on the service class or on a service method (or both).</p> <p>The following decorators are available:</p> <table> <thead> <tr> <th>Decorator</th> <th>Description</th> </tr> </thead> <tbody> <tr> <td>AcceptLanguage</td> <td>Tell the <a href="classes/_server_.server.html">Server</a> that a class or a method should only accept requests from clients that accepts one of the supported languages. </td> </tr> <tr> <td>Accept</td> <td>Tell the <a href="classes/_server_.server.html">Server</a> that a class or a method should only accept requests from clients that accepts one of the supported mime types. </td> </tr> </tbody> </table> <p>See some examples:</p> <pre><code class="lang-typescript">@Path(<span class="hljs-string">"test"</span>) @AcceptLanguage(<span class="hljs-string">"en"</span>, <span class="hljs-string">"pt-BR"</span>) <span class="hljs-keyword">class</span> TestAcceptService { @GET testLanguage(@ContextLanguage language: <span class="hljs-built_in">string</span>): <span class="hljs-built_in">string</span> { <span class="hljs-keyword">if</span> (language === <span class="hljs-string">'en'</span>) { <span class="hljs-keyword">return</span> <span class="hljs-string">"accepted"</span>; } <span class="hljs-keyword">return</span> <span class="hljs-string">"aceito"</span>; } } </code></pre> <p>In the above example, we declare that only <code>English</code> and <code>Brazilian Portuguese</code> are supported. The order here is important. That declaration says that our first language is <code>English</code>. So, if nothing was specified by the request, or if these two languages has the same weight on the resquest <code>Accept-Language</code> header, <code>English</code> will be the choice. </p> <p>If the request specifies an <code>Accept-Language</code> header, we will choose the language that best fit the header value, considering the list of possible values declared on <code>@AcceptLanguage</code> decorator.</p> <p>If none of our possibilities is good for the <code>Accept-Language</code> header in the request, the server throws a <code>NotAcceptableError</code> and returns a <code>406</code> status code for the client.</p> <p>You can decorate methods too, like:</p> <pre><code class="lang-typescript">@Path(<span class="hljs-string">"test"</span>) @AcceptLanguage(<span class="hljs-string">"en"</span>, <span class="hljs-string">"pt-BR"</span>) <span class="hljs-keyword">class</span> TestAcceptService { @GET @AcceptLanguage(<span class="hljs-string">"fr"</span>) testLanguage(@ContextLanguage language: <span class="hljs-built_in">string</span>): <span class="hljs-built_in">string</span> { <span class="hljs-comment">// ...</span> } } </code></pre> <p>On the above example, the list of accepted languages will be <code>[&quot;en&quot;, &quot;pt-BR&quot;, &quot;fr&quot;]</code>, in that order.</p> <p>The <code>@Accept</code> decorator works exaclty like <code>@AcceptLanguage</code>, but it inform the server about the mime type that a service can provide. It uses the <code>Accept</code> header in the request to decide about the preferred media to use.</p> <pre><code class="lang-typescript">@Path(<span class="hljs-string">"test"</span>) @Accept(<span class="hljs-string">"application/json"</span>) <span class="hljs-keyword">class</span> TestAcceptService { @GET testType(@ContextAccept accept: <span class="hljs-built_in">string</span>): <span class="hljs-built_in">string</span> { <span class="hljs-comment">//...</span> } } </code></pre> </div> </div> <div class="col-4 col-menu menu-sticky-wrap menu-highlight"> <nav class="tsd-navigation primary"> <ul> <li class="globals "> <a href="globals.html"><em>Globals</em></a> </li> <li class=" tsd-kind-external-module"> <a href="modules/_decorators_.html">"decorators"</a> </li> <li class=" tsd-kind-external-module"> <a href="modules/_es5_compat_.html">"es5-<wbr>compat"</a> </li> <li class=" tsd-kind-external-module"> <a href="modules/_metadata_.html">"metadata"</a> </li> <li class=" tsd-kind-external-module"> <a href="modules/_server_.html">"server"</a> </li> <li class=" tsd-kind-external-module"> <a href="modules/_server_container_.html">"server-<wbr>container"</a> </li> <li class=" tsd-kind-external-module"> <a href="modules/_server_errors_.html">"server-<wbr>errors"</a> </li> <li class=" tsd-kind-external-module"> <a href="modules/_server_return_.html">"server-<wbr>return"</a> </li> <li class=" tsd-kind-external-module"> <a href="modules/_server_types_.html">"server-<wbr>types"</a> </li> <li class=" tsd-kind-external-module"> <a href="modules/_typescript_rest_.html">"typescript-<wbr>rest"</a> </li> </ul> </nav> <nav class="tsd-navigation secondary menu-sticky"> <ul class="before-current"> </ul> </nav> </div> </div> </div> <footer class="with-border-bottom"> <div class="container"> <h2>Legend</h2> <div class="tsd-legend-group"> <ul class="tsd-legend"> <li class="tsd-kind-module"><span class="tsd-kind-icon">Module</span></li> <li class="tsd-kind-object-literal"><span class="tsd-kind-icon">Object literal</span></li> <li class="tsd-kind-variable"><span class="tsd-kind-icon">Variable</span></li> <li class="tsd-kind-function"><span class="tsd-kind-icon">Function</span></li> <li class="tsd-kind-function tsd-has-type-parameter"><span class="tsd-kind-icon">Function with type parameter</span></li> <li class="tsd-kind-index-signature"><span class="tsd-kind-icon">Index signature</span></li> <li class="tsd-kind-type-alias"><span class="tsd-kind-icon">Type alias</span></li> </ul> <ul class="tsd-legend"> <li class="tsd-kind-enum"><span class="tsd-kind-icon">Enumeration</span></li> <li class="tsd-kind-enum-member"><span class="tsd-kind-icon">Enumeration member</span></li> <li class="tsd-kind-property tsd-parent-kind-enum"><span class="tsd-kind-icon">Property</span></li> <li class="tsd-kind-method tsd-parent-kind-enum"><span class="tsd-kind-icon">Method</span></li> </ul> <ul class="tsd-legend"> <li class="tsd-kind-interface"><span class="tsd-kind-icon">Interface</span></li> <li class="tsd-kind-interface tsd-has-type-parameter"><span class="tsd-kind-icon">Interface with type parameter</span></li> <li class="tsd-kind-constructor tsd-parent-kind-interface"><span class="tsd-kind-icon">Constructor</span></li> <li class="tsd-kind-property tsd-parent-kind-interface"><span class="tsd-kind-icon">Property</span></li> <li class="tsd-kind-method tsd-parent-kind-interface"><span class="tsd-kind-icon">Method</span></li> <li class="tsd-kind-index-signature tsd-parent-kind-interface"><span class="tsd-kind-icon">Index signature</span></li> </ul> <ul class="tsd-legend"> <li class="tsd-kind-class"><span class="tsd-kind-icon">Class</span></li> <li class="tsd-kind-class tsd-has-type-parameter"><span class="tsd-kind-icon">Class with type parameter</span></li> <li class="tsd-kind-constructor tsd-parent-kind-class"><span class="tsd-kind-icon">Constructor</span></li> <li class="tsd-kind-property tsd-parent-kind-class"><span class="tsd-kind-icon">Property</span></li> <li class="tsd-kind-method tsd-parent-kind-class"><span class="tsd-kind-icon">Method</span></li> <li class="tsd-kind-accessor tsd-parent-kind-class"><span class="tsd-kind-icon">Accessor</span></li> <li class="tsd-kind-index-signature tsd-parent-kind-class"><span class="tsd-kind-icon">Index signature</span></li> </ul> <ul class="tsd-legend"> <li class="tsd-kind-constructor tsd-parent-kind-class tsd-is-inherited"><span class="tsd-kind-icon">Inherited constructor</span></li> <li class="tsd-kind-property tsd-parent-kind-class tsd-is-inherited"><span class="tsd-kind-icon">Inherited property</span></li> <li class="tsd-kind-method tsd-parent-kind-class tsd-is-inherited"><span class="tsd-kind-icon">Inherited method</span></li> <li class="tsd-kind-accessor tsd-parent-kind-class tsd-is-inherited"><span class="tsd-kind-icon">Inherited accessor</span></li> </ul> <ul class="tsd-legend"> <li class="tsd-kind-property tsd-parent-kind-class tsd-is-protected"><span class="tsd-kind-icon">Protected property</span></li> <li class="tsd-kind-method tsd-parent-kind-class tsd-is-protected"><span class="tsd-kind-icon">Protected method</span></li> <li class="tsd-kind-accessor tsd-parent-kind-class tsd-is-protected"><span class="tsd-kind-icon">Protected accessor</span></li> </ul> <ul class="tsd-legend"> <li class="tsd-kind-property tsd-parent-kind-class tsd-is-private"><span class="tsd-kind-icon">Private property</span></li> <li class="tsd-kind-method tsd-parent-kind-class tsd-is-private"><span class="tsd-kind-icon">Private method</span></li> <li class="tsd-kind-accessor tsd-parent-kind-class tsd-is-private"><span class="tsd-kind-icon">Private accessor</span></li> </ul> <ul class="tsd-legend"> <li class="tsd-kind-property tsd-parent-kind-class tsd-is-static"><span class="tsd-kind-icon">Static property</span></li> <li class="tsd-kind-call-signature tsd-parent-kind-class tsd-is-static"><span class="tsd-kind-icon">Static method</span></li> </ul> </div> </div> </footer> <div class="container tsd-generator"> <p>Generated using <a href="http://typedoc.io" target="_blank">TypeDoc</a></p> </div> <div class="overlay"></div> <script src="assets/js/main.js"></script> <script>if (location.protocol == 'file:') document.write('<script src="assets/js/search.js"><' + '/script>');</script> </body> </html>