rayepps / exobase-js Goto Github PK
View Code? Open in Web Editor NEWA library that implements the Abstract & Compose design pattern, write you API or web service on any framework -- then switch.
Home Page: exobase-js.vercel.app
A library that implements the Abstract & Compose design pattern, write you API or web service on any framework -- then switch.
Home Page: exobase-js.vercel.app
Exobase should statically validate (using types) that a hook cannot be used if an incompatible hook was used in the composition (or chain) already.
Using useLambda
with an SQS trigger with an http hook like useJsonArgs
or usePathParams
I've got a large project using Exobase and I have the same pattern in my endpoints:
export const handler = _.compose(
useLambda(),
useCatch((props, error) => {
if (error.error instanceof ExobaseError) {
const ret = {
...props.response,
status: error.error.status,
body: { message: error.error.message },
key: error.error.key,
};
return ret;
}
throw error;
}),
useCors(),
...
);
Is there a way to compose useLambda
, useCatch
, and useCors
into a single hook that I can include in all my endpoints? I've mucked around with compose
and chain
from radash
, but I haven't been able to get that working.
I'd like the option to pass the "strict" option to the call to zod.object
in useQueryString so that I can immediately return an error on an unrecognized query param. I've implemented it myself like so:
export const useQueryString: <TArgs extends {}, TProps extends Props = Props>(
shapeMaker: (z: Zod) => KeyOfType<TArgs, any>,
strict?: boolean
) => (
func: Handler<
TProps & {
args: TProps['args'] & TArgs;
}
>
) => Handler<TProps> = (shapeMaker, strict) => (func) => {
let model: AnyZodObject;
if (strict) {
model = zod.object(shapeMaker(zod)).strict();
} else {
model = zod.object(shapeMaker(zod));
}
return (props) => withQueryString(func as Handler, model, null, props);
};
So how do you do dependency injection for testing with this framework? Say I have a function, listThings
, implemented like so:
import type { Props } from '@exobase/core';
import makeStorageService, {
StorageService,
} from '../storage-service';
import { useService } from '@exobase/hooks';
import _ from 'radash';
import config from '../config';
interface Args {
listThingsArgs: any;
}
interface Services {
storage: StorageService;
}
type Response = Array<string>;
async function listThings({args, services}: Props<Args, Services>): Promise<Response> {
return this.services.storage.listThings(args.listThingsArgs)
}
export default _.compose(
useService<Services>({
storage: await makeStorageService(config.storageService)
}),
listThings
);
(As I'm sure you can deduce, I lifted a lot of this pattern from your published endpoint code)
So two things to note here:
First, there's no framework code here. While this is intended to run in Lambda / API Gateway, my goal is to be able to compose the framework code from Exobase with my function code so that I can very easily port this to another framework if need be.
Second, I'm loading my config
in the function definiiton for listThings
. If I want to use a custom config
for my tests, how am I supposed to inject that? Or should I just mock the call to makeStorageService
?
I'd like a hook that allows me to extract { path: 'foo/bar' }
from the path /my/endpoint/foo/bar
where the endpoint is defined in the API as /my/endpoint/{path}
. I've implemented it in my own project as follows, but I didn't want to submit a PR as I don't have tests defined for it and I don't know where it would be appropriate to put it in the codebase, as it's a hook but an API Gateway specific hook.
export { useJsonArgs, useQueryArgs, useHeaderArgs } from '@exobase/hooks';
import { partial } from 'radash';
import { useValidation } from '@exobase/hooks';
import { Props, ApiFunction, Request } from '@exobase/core';
import { APIGatewayProxyEvent } from 'aws-lambda';
import * as yup from 'yup';
type APIGatewayProxyRequest = Request & { event: APIGatewayProxyEvent };
type Yup = typeof yup;
type KeyOfType<T, Value> = { [P in keyof T]: Value };
/**
* Get args from the parsed path parameters (AWS API Gateway-specific)
*/
export const useLambdaPathArgs = partial(
useValidation,
(props: Props<any, any, any, APIGatewayProxyRequest>) =>
props.req.event.pathParameters
) as <TArgs = any>(
shapeMaker: (yup: Yup) => KeyOfType<TArgs, any>
) => (func: ApiFunction) => ApiFunction;
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.