Skip to content

Instantly share code, notes, and snippets.

@AlexGeb
Created May 3, 2024 07:18
Show Gist options
  • Save AlexGeb/6bcab58a8f7178833e75059232c6b886 to your computer and use it in GitHub Desktop.
Save AlexGeb/6bcab58a8f7178833e75059232c6b886 to your computer and use it in GitHub Desktop.
Example of use of effect platform HttpClient to wrap an api call into a service
import { HttpClient } from '@effect/platform';
import { Schema } from '@effect/schema';
import { Failure, utils } from '@inato/shared-kernel';
import { Effect, Layer, flow } from 'effect';
import { UrlShorteningService } from '~/application/services/UrlShorteningService';
class Response extends Schema.Class<Response>('Response')({
data: Schema.Struct({ tiny_url: utils.CustomSchemas.URL }),
}) {
static decodeResponse = HttpClient.response.schemaBodyJsonScoped(Response);
}
const RequestBody = Schema.Struct({
domain: Schema.Literal('m.inato.com'),
url: Schema.String,
});
const makeService = ({ apiToken }: { apiToken: string }) =>
Effect.gen(function* (_) {
const requestHeaders = {
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
};
const addBody = HttpClient.request.schemaBody(RequestBody);
const httpClient = yield* HttpClient.client.Client.pipe(
Effect.map(HttpClient.client.filterStatusOk),
Effect.map(
HttpClient.client.mapRequest(
flow(
HttpClient.request.prependUrl('https://api.tinyurl.com'),
HttpClient.request.setHeaders(requestHeaders),
),
),
),
);
const shorten = (url: string) =>
HttpClient.request.post('/create').pipe(
addBody({ url, domain: 'm.inato.com' }),
Effect.flatMap(httpClient),
Response.decodeResponse,
Effect.map(decodedResponse => decodedResponse.data.tiny_url),
Effect.catchTags({
BodyError: Effect.die,
ParseError: Failure.Effect.unexpectedFromParseError,
RequestError: Effect.die,
ResponseError: e =>
Effect.fail(
Failure.unexpected(`[TinyUrl] ${e.message}`, e.cause).addContext({
apiResponse: JSON.stringify({
data: e.response.json,
status: e.response.status,
}),
}),
),
}),
);
return { shorten };
});
export const TinyUrlShorteningService = {
layer: ({ apiToken }: { apiToken: string }) =>
Layer.effect(UrlShorteningService.Tag, makeService({ apiToken })).pipe(
Layer.provide(HttpClient.client.layer),
),
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment