Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Passing route information to template engine #142

Merged
merged 3 commits into from
Feb 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export class ResponseSampler extends SchemaParserMiddleware {
{
parameters: schema.sample.parameters,
profileName: schema.sample.profile,
req: schema.sample?.req,
},
// We only need the columns of this query, so we set offset=0 and limit=1 here.
// Some drivers guess the column types by data, so we should at least query 1 rows.
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/lib/template-engine/compiler.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DataResult } from '@vulcan-sql/core/models';
import { DataResult, KoaRequest } from '@vulcan-sql/core/models';
import { Pagination } from '../../models/pagination';

export interface TemplateLocation {
Expand Down Expand Up @@ -31,6 +31,7 @@ export interface ExecuteContext {
parameters?: Record<string, any>;
user?: UserInfo;
profileName: string;
req?: KoaRequest;
}

export interface Compiler {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as nunjucks from 'nunjucks';
import { ExecuteContext, UserInfo } from './compiler';
import { KoaRequest } from '@vulcan-sql/core/models';

export const ReservedContextKeys = {
CurrentProfileName: 'RESERVED_CURRENT_PROFILE_NAME',
Expand All @@ -10,18 +11,21 @@ export class NunjucksExecutionMetadata {
private profileName: string;
private parameters: Record<string, any>;
private userInfo?: UserInfo;
private req?: KoaRequest;

constructor({ parameters = {}, profileName, user }: ExecuteContext) {
constructor({ parameters = {}, profileName, user, req }: ExecuteContext) {
this.parameters = parameters;
this.profileName = profileName;
this.userInfo = user;
this.req = req;
}

/** Load from nunjucks context */
static load(context: nunjucks.Context) {
return new NunjucksExecutionMetadata({
parameters: context.lookup('context')?.params || {},
user: context.lookup('context')?.user || {},
req: context.lookup('context')?.req || {},
profileName: context.lookup(ReservedContextKeys.CurrentProfileName)!,
});
}
Expand All @@ -32,6 +36,7 @@ export class NunjucksExecutionMetadata {
context: {
params: this.parameters,
user: this.userInfo,
req: this.req,
profile: this.profileName,
},
[ReservedContextKeys.CurrentProfileName]: this.profileName,
Expand All @@ -45,4 +50,8 @@ export class NunjucksExecutionMetadata {
public getUserInfo() {
return this.userInfo;
}

public getRequest() {
return this.req;
}
}
4 changes: 4 additions & 0 deletions packages/core/src/models/artifact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ import {
} from '../lib/validators/constraints';
import { Type } from 'class-transformer';
import 'reflect-metadata';
import { Request as KoaRequest } from 'koa';

export type { KoaRequest };

// Pagination mode should always be UPPERCASE because schema parser will transform the user inputs.
export enum PaginationMode {
Expand Down Expand Up @@ -88,6 +91,7 @@ export class ErrorInfo {
export class Sample {
profile!: string;
parameters!: Record<string, any>;
req?: KoaRequest;
}

export class APISchema {
Expand Down
20 changes: 20 additions & 0 deletions packages/doc/docs/api-building/sql-syntax.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,26 @@ from app_data.payments

VulcanSQL will provide the feature by enhancing the [nunjucks](https://mozilla.github.io/nunjucks/templating.html#tags) macro function by importing a macro function from other files in the next version 😃

## Useing HTTP Request data in SQL file

You can easily use `{{ context.req.xxx }}` in the sql file to obtain data from the http request or a custom header as a query condition.

the syntax like the below:

```sql
select
*
from
"artists"
where
{{ context.req.method }} = 'GET'
and
{{ context.req.header.customParameters }} = 'custom parameters'
......
```

For more available parameters, please refer to: [Koajs#Request](https://koajs.com/#request)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another suggestion is that a sample for using sample in the api schema file, because if user would like to make the build time work with sample, he should also add the req to sample:

-- We use the req in sql file
select 
*,
{{ context.req.method }} as "req-method",
{{ context.req.url }} as "req-url"
from "artists"
where 
ConstituentID = {{ context.params.id }}
and
 {{ context.req.method }} = 'GET'
# API Schema
urlPath: /artist/:id
request:
  - fieldName: id
    fieldIn: path
    description: constituent id
    validators:
      - required
sample:
  req:
    method: GET
    url: 'localhost:3000'
  parameters:
    id: '1'
  profile: duck
profile: duck

``

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, @kokokuo , I found that there is already a section about set-sampler in the document. Maybe we can update this section to inform the user on how to properly configure it.

Copy link
Contributor

@kokokuo kokokuo Feb 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you open an issue to record the improvement content ? cc @JSYOU

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @JSYOU adding the issue with sample, I record at here #146


## Set variable

You could set the variable not only primitive value e.g: integer, string, array. But also VulcanSQL support declares a variable by assigning the dynamic parameter to it. Use the `set` tag and `{% ... %}` to declare the variable and set:
Expand Down
8 changes: 7 additions & 1 deletion packages/serve/src/lib/route/route-component/baseRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { IRequestValidator } from './requestValidator';
import { IRequestTransformer, RequestParameters } from './requestTransformer';
import { IPaginationTransformer } from './paginationTransformer';
import { Evaluator } from '@vulcan-sql/serve/evaluator';
import { KoaRequest } from '@vulcan-sql/core';

export interface TransformedRequest {
reqParams: RequestParameters;
Expand Down Expand Up @@ -57,7 +58,11 @@ export abstract class BaseRoute implements IRoute {

protected abstract prepare(ctx: KoaContext): Promise<TransformedRequest>;

protected async handle(user: AuthUserInfo, transformed: TransformedRequest) {
protected async handle(
user: AuthUserInfo,
transformed: TransformedRequest,
req: KoaRequest
) {
const { reqParams, pagination } = transformed;
// could template name or template path, use for template engine
const { templateSource, profiles } = this.apiSchema;
Expand All @@ -74,6 +79,7 @@ export abstract class BaseRoute implements IRoute {
{
parameters: reqParams,
user,
req,
profileName: profile,
},
pagination
Expand Down
4 changes: 3 additions & 1 deletion packages/serve/src/lib/route/route-component/graphQLRoute.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* istanbul ignore file */
import { BaseRoute, RouteOptions } from './baseRoute';
import { KoaContext } from '@vulcan-sql/serve/models';
import { KoaRequest } from '@vulcan-sql/core';

export class GraphQLRoute extends BaseRoute {
public readonly operationName: string;
Expand All @@ -18,7 +19,8 @@ export class GraphQLRoute extends BaseRoute {
public async respond(ctx: KoaContext) {
const transformed = await this.prepare(ctx);
const authUser = ctx.state.user;
await this.handle(authUser, transformed);
const req = ctx.request as KoaRequest;
await this.handle(authUser, transformed, req);
// TODO: get template engine handled result and return response by checking API schema
return transformed;
}
Expand Down
5 changes: 4 additions & 1 deletion packages/serve/src/lib/route/route-component/restfulRoute.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { BaseRoute, RouteOptions } from './baseRoute';
import { KoaContext } from '@vulcan-sql/serve/models';
import { KoaRequest } from '@vulcan-sql/core';

export class RestfulRoute extends BaseRoute {
public readonly urlPath: string;

Expand All @@ -12,7 +14,8 @@ export class RestfulRoute extends BaseRoute {
public async respond(ctx: KoaContext) {
const transformed = await this.prepare(ctx);
const authUser = ctx.state.user;
const result = await this.handle(authUser, transformed);
const req = ctx.request as KoaRequest;
const result = await this.handle(authUser, transformed, req);
ctx.response.body = {
data: result.getData(),
columns: result.getColumns(),
Expand Down