-
Notifications
You must be signed in to change notification settings - Fork 106
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'develop' into docs/batching
- Loading branch information
Showing
23 changed files
with
574 additions
and
187 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,4 +21,5 @@ yarn-error.log* | |
.yarn/ | ||
|
||
.idea/ | ||
src/*/*.json | ||
src/*/*.json | ||
.vscode/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
--- | ||
title: Installation | ||
sidebar_position: 1 | ||
sidebar_position: 2 | ||
slug: /getting_started | ||
--- | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
--- | ||
title: Introduction | ||
sidebar_position: 1 | ||
slug: / | ||
--- | ||
|
||
Good APIs craft a broad spectrum of functionalities. Yet, the broader their scope, the more they diverge from being the perfect fit for any specific use case. This fundamental discrepancy — the impedance mismatch between the general capabilities of an API and the precise needs of a particular scenario — amplifies the necessity for an orchestration layer. Such a layer adeptly bridges this gap, tailor-fitting generic APIs to meet exact requirements with finesse. Tailcall stands at the forefront of this innovation, seamlessly transforming the way APIs are integrated and interacted with. | ||
|
||
Tailcall introduces a robust DSL (Domain-Specific Language), enabling developers to fine-tune how APIs are orchestrated. This DSL facilitates specifying different caching and batching strategies to enhance the system's efficiency. It also enables precise governance and access control mechanisms. Tailcall serves as a central hub for team collaboration, offering a unified point for managing all APIs, documentation, and more. Once configured, it positions itself between the clients and microservices, adeptly managing all requests and orchestrating them as needed. | ||
|
||
![Architecture Diagram](/images/docs/architecture.png) | ||
|
||
Manually crafting BFF (Backend for Frontend) layers has become outdated. With Tailcall, API orchestration evolves into a streamlined and highly optimized process. It functions as an essential intermediary, intelligently directing requests and assembling responses from each microservice. This approach diminishes the development burden associated with traditional BFF layers but also bolsters performance, reliability, and scalability throughout the application infrastructure. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
--- | ||
title: Http Cache | ||
description: A comprehensive guide to leverage HTTP cache for REST APIs using Tailcall | ||
--- | ||
|
||
HTTP Caching in Tailcall is designed to enhance performance and minimize the frequency of requests to upstream services by caching HTTP responses. This guide explains the concept, benefits, and how to effectively implement HTTP caching within Tailcall. | ||
|
||
### Understanding HTTP Caching | ||
|
||
HTTP Caching involves saving copies of HTTP responses to serve identical future requests directly from the cache, bypassing the need for new API calls. This reduces latency, conserves bandwidth, and alleviates the load on upstream services by utilizing a cache keyed by request URLs and headers. | ||
|
||
By default, HTTP caching is turned off in Tailcall. Enabling it requires setting the `httpCache` parameter to `true` in the `@upstream` configuration. Tailcall employs a in-memory _Least_Recently_Used_ (LRU) cache mechanism to manage stored responses, adhering to upstream-provided caching directives like `Cache-Control` to optimize the caching process and minimize redundant upstream API requests. | ||
|
||
### Enabling HTTP Caching | ||
|
||
To activate HTTP caching, adjust the upstream configuration in Tailcall by setting `httpCache` to `true`, as shown in the following example: | ||
|
||
```graphql | ||
schema | ||
@server(port: 4000) | ||
@upstream( | ||
baseURL: "https://api.example.com" | ||
# highlight-start | ||
httpCache: true | ||
# highlight-end | ||
) { | ||
query: Query | ||
} | ||
``` | ||
|
||
This configuration instructs Tailcall to cache responses from the designated upstream API. | ||
|
||
### Cache-Control headers in responses | ||
|
||
Enabling the `cacheControlHeader` setting in Tailcall ensures that [Cache-Control] headers are included in the responses returned to clients. When activated, Tailcall dynamically sets the `max-age` directive in the `Cache-Control` header to the minimum `max-age` value encountered in any of the responses from upstream services. This approach guarantees that the caching duration for the composite response is conservative, aligning with the shortest cache validity period provided by the upstream services. By default, this feature is disabled (`false`), meaning Tailcall will not modify or add `Cache-Control` headers unless explicitly instructed to do so. This setting is distinct from the general HTTP cache setting, which controls whether responses are cached internally by Tailcall; `cacheControlHeader` specifically controls the caching instructions sent to clients. | ||
|
||
Here is how you can enable the `cacheControlHeader` setting within your Tailcall schema to apply these caching instructions: | ||
|
||
```graphql | ||
schema @server(cacheControlHeader: true) { | ||
query: Query | ||
mutation: Mutation | ||
} | ||
``` | ||
|
||
[cache-control]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control | ||
|
||
### Best Practices for Enhancing REST API Performance with Tailcall | ||
|
||
The combination of `httpCache` and `cacheControlHeader` provides a comprehensive caching solution. While `httpCache` focuses on internal caching to reduce the impact of high latency and frequent requests, `cacheControlHeader` manages client-side caching policies, ensuring an optimal balance between performance, data freshness, and efficient resource use. | ||
|
||
These caching primitives are beneficial for REST APIs that are latency-sensitive, have a high rate of request repetition, or come with explicit caching headers indicating cacheable responses. Together, they tackle the common challenges of optimizing REST API performance by minimizing unnecessary network traffic and server load while ensuring response accuracy. | ||
|
||
To further enhance the performance of any API with Tailcall, integrating the [@cache] directive offers protocol agnostic control over caching at the field level within a GraphQL schema. | ||
|
||
[@cache]: /docs/operators/cache.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
--- | ||
title: HTTP Filters | ||
description: Modify upstream requests and responses using Javascript | ||
--- | ||
|
||
Tailcall provides a light-weight JS runtime to modify requests and resolve with custom responses. | ||
The runtime is not a full-fledged Node.js environment and has no access to the file system or the network. It is designed to be used for simple request/response modifications. | ||
|
||
## Getting Started | ||
|
||
To leverage this functionality, a JavaScript function named `onRequest` must be created in a `worker.js` file. This function serves as middleware, allowing for the interception and modification of the request. Here is a simple example of a `worker.js` file that logs the request and returns the original request without any modifications. | ||
|
||
```javascript | ||
function onRequest({request}) { | ||
console.log(`${request.method} ${request.url}`) | ||
|
||
return {request} | ||
} | ||
``` | ||
|
||
Once you have a worker file ready, you link that file to the tailcall configuration using the [@link] operator. | ||
|
||
[@link]: /docs/operators/link | ||
|
||
```graphql | ||
schema @link(type: Script, src: "./worker.js") { | ||
query: Query | ||
} | ||
``` | ||
|
||
Once the worker is linked, you can start the server using the usual [start] command. Making requests to tailcall will now be intercepted by the worker and logged to the console. | ||
|
||
[start]: /docs/guides/cli/#start | ||
|
||
## Modify Request | ||
|
||
You can modify the request by returning a `request` object from the `onRequest` function. Below is an example where we are modifying the request to add a custom header. | ||
|
||
```javascript | ||
function onRequest({request}) { | ||
request.headers["x-custom-header"] = "Hello, Tailcall!" | ||
|
||
return {request} | ||
} | ||
``` | ||
|
||
## Create Response | ||
|
||
You can respond with custom responses by returning a `response` object from the `onRequest` function. Below is an example where we are responding with a custom response for all requests that start with `https://api.example.com`. | ||
|
||
```javascript | ||
function onRequest({request}) { | ||
if (request.url.startsWith("https://api.example.com")) { | ||
return { | ||
response: { | ||
status: 200, | ||
headers: { | ||
"content-type": "application/json" | ||
}, | ||
body: JSON.stringify({message: "Hello, Tailcall!"}) | ||
} | ||
} | ||
} | ||
else { | ||
return {request} | ||
} | ||
``` | ||
## Response Redirect | ||
Sometimes you might want to redirect the request to a different URL. You can do this by returning a `response` object with a `status` of `301` or `302` and a `Location` header. The following example redirects all requests to `https://example.com` to `https://tailcall.com`. | ||
|
||
```javascript | ||
function onRequest({request}) { | ||
if (request.url.startsWith("https://example.com")) { | ||
return { | ||
response: { | ||
status: 301, | ||
headers: { | ||
Location: "https://tailcall.com", | ||
}, | ||
}, | ||
} | ||
} else { | ||
return {request} | ||
} | ||
} | ||
``` | ||
|
||
:::important | ||
The new request that's created as a result of the redirect will not be intercepted by the worker. | ||
::: | ||
## Schema | ||
The `onRequest` function takes a single argument that contains the request object. The return value of the `onRequest` function can be a `request` object, or a `response` object. It can not be null or undefined. | ||
**Request** | ||
The request object has the following shape: | ||
```typescript | ||
type Request = { | ||
method: string | ||
url: string | ||
headers: {[key: string]: string} | ||
body?: string | ||
} | ||
``` | ||
The http filter doesn't have access to the request's body. However the modified request that's returned can optionally provide the body. | ||
|
||
**Response** | ||
|
||
The response object has the following shape: | ||
|
||
```typescript | ||
type Response = { | ||
status: number | ||
headers: {[key: string]: string} | ||
body?: string | ||
} | ||
``` |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.