|- services/
|- foo-api/
|- index.ts # entry point for the repo
|- foo-api.ts
|- foo-api-service/
|- index.ts # entry point for the service, exports all
|- foo-api-service.ts
|- some-method.ts
A repository is an abstraction over a service (api, db, etc...).
example, simple API Service
// ./services/foo-api/index.ts
export * from './foo-api';
// ./services/foo-api/foo-api.ts
import axios from 'axios';
import {Context, Effect, Layer, Config, LogLevel, pipe} from 'effect';
export const FOO_API_BASE_URL = pipe(
Config.nonEmptyString('FOO_API_BASE_URL'),
// same host used for all environments
Config.withDefault('https://api.foo.com'),
);
export const FOO_API_TOKEN = Config.nonEmptyString('FOO_API_TOKEN');
export const createFooApi = Effect.gen(function* () {
const baseURL = yield* FOO_API_BASE_URL;
const token = yield* FOO_API_TOKEN;
return axios.create({baseURL, headers: {'X-FOO-TOKEN': token}});
});
export class FooApi extends Context.Tag('FooApi')<
FooApi,
Effect.Effect.Success<typeof createFooApi>
>() {
static Live = Layer.effect(this, createFooApi);
}
A service is built on top of a repository (or multiple repositories) and provides Mavely specific functionality.
// ./services/foo-api-service/index.ts
export * from './foo-api-service';
// ./services/foo-api-service/some-method.ts
import {Array, Effect, Schema, Struct, pipe} from 'effect';
import {FooApi} from '../foo-api';
export const someMethod = (entityId: string) =>
Effect.gen(function* () {
const prisma = yield* Prisma;
const fooApi = yield* FooApi;
return yield* pipe(
Effect.tryPromise(() => fooApi.get(`/some-endpoint/${entityId}`)),
Effect.map(Struct.get('data')),
Effect.flatMap(
Schema.decodeUnknown(Schema.Struct({result: Struct.String})),
),
Effect.map(Struct.get('result')),
Effect.flatMap(result => prisma.user.findUnique({where: {id: result}})),
// do more stuff
);
});
// ./services/foo-api-service/foo-api-service.ts
import {Context, Layer} from 'effect';
import {someMethod} from './some-method';
export const createFooApiService = () => ({someMethod});
export class FooApiService extends Context.Tag('FooApiService')<
FooApiService,
ReturnType<typeof createFooApiService>
>() {
static Live = Layer.succeed(this, createFooApiService());
}
TODO: Show using this repo/service from a top level program
how do you feel about extended filetypes here, e.g.
foo-api.service.ts
. that is one of the things I kinda like from nest