Add fococoffee endpoints
This commit is contained in:
@@ -23,6 +23,7 @@ import { RedirectsModule } from './redirects/redirects.module';
|
|||||||
import { FileModule } from './file/file.module';
|
import { FileModule } from './file/file.module';
|
||||||
import { FocoLiveModule } from './foco-live/foco-live.module';
|
import { FocoLiveModule } from './foco-live/foco-live.module';
|
||||||
import { PowModule } from './pow/pow.module';
|
import { PowModule } from './pow/pow.module';
|
||||||
|
import { FocoCoffeeModule } from './fococoffee/fococoffee.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -80,6 +81,7 @@ import { PowModule } from './pow/pow.module';
|
|||||||
FileModule,
|
FileModule,
|
||||||
FocoLiveModule,
|
FocoLiveModule,
|
||||||
PowModule,
|
PowModule,
|
||||||
|
FocoCoffeeModule,
|
||||||
],
|
],
|
||||||
controllers: [AppController],
|
controllers: [AppController],
|
||||||
providers: [AppService],
|
providers: [AppService],
|
||||||
|
16
src/fococoffee/bindle.service.ts
Normal file
16
src/fococoffee/bindle.service.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { ShopifyProduct, parseShopifyProduct } from './shopifyUtils';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class BindleService {
|
||||||
|
public readonly shopifyUrl = 'https://bindlecoffee.com/products.json'
|
||||||
|
|
||||||
|
public async fetchProducts(): Promise<ShopifyProduct<Date>[]> {
|
||||||
|
const response = await axios.get(this.shopifyUrl)
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error('Failed to fetch products')
|
||||||
|
}
|
||||||
|
return response.data.products.map(parseShopifyProduct);
|
||||||
|
}
|
||||||
|
}
|
48
src/fococoffee/fococoffee.controller.ts
Normal file
48
src/fococoffee/fococoffee.controller.ts
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import { Controller, Get } from '@nestjs/common';
|
||||||
|
import { HarbingerService } from './harbinger.service';
|
||||||
|
import { FocoCoffeeService } from './fococoffee.service';
|
||||||
|
import { LimaService } from './lima.service';
|
||||||
|
import { BindleService } from './bindle.service';
|
||||||
|
import { ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
@Controller('fococoffee')
|
||||||
|
@ApiTags('fococoffee')
|
||||||
|
export class FocoCoffeeController {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly focoCoffeeService: FocoCoffeeService,
|
||||||
|
private readonly harbingerService: HarbingerService,
|
||||||
|
private readonly limaService: LimaService,
|
||||||
|
private readonly bindleService: BindleService
|
||||||
|
) { }
|
||||||
|
|
||||||
|
@Get('harbinger/products')
|
||||||
|
@ApiResponse({ status: 200, description: 'Returns the list of Harbinger products' })
|
||||||
|
async getHarbingerProducts() {
|
||||||
|
return this.harbingerService.fetchProducts()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('lima/products')
|
||||||
|
@ApiResponse({ status: 200, description: 'Returns the list of Lima products' })
|
||||||
|
async getLimaProducts() {
|
||||||
|
return this.limaService.fetchProducts()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('bindle/products')
|
||||||
|
@ApiResponse({ status: 200, description: 'Returns the list of Bindle products' })
|
||||||
|
async getBindleProducts() {
|
||||||
|
return this.bindleService.fetchProducts()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('beans')
|
||||||
|
@ApiResponse({ status: 200, description: 'Returns the list of coffee bean products from all suppliers' })
|
||||||
|
async getBeans() {
|
||||||
|
return this.focoCoffeeService.getBeans()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('products')
|
||||||
|
@ApiResponse({ status: 200, description: 'Returns the list of all products from all suppliers' })
|
||||||
|
async getAllProducts() {
|
||||||
|
return this.focoCoffeeService.getAllProducts()
|
||||||
|
}
|
||||||
|
}
|
13
src/fococoffee/fococoffee.module.ts
Normal file
13
src/fococoffee/fococoffee.module.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { FocoCoffeeController } from './fococoffee.controller';
|
||||||
|
import { FocoCoffeeService } from './fococoffee.service';
|
||||||
|
import { HarbingerService } from './harbinger.service';
|
||||||
|
import { LimaService } from './lima.service';
|
||||||
|
import { BindleService } from './bindle.service';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [],
|
||||||
|
controllers: [FocoCoffeeController],
|
||||||
|
providers: [FocoCoffeeService, HarbingerService, LimaService, BindleService]
|
||||||
|
})
|
||||||
|
export class FocoCoffeeModule { }
|
39
src/fococoffee/fococoffee.service.ts
Normal file
39
src/fococoffee/fococoffee.service.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { LimaService } from './lima.service';
|
||||||
|
import { HarbingerService } from './harbinger.service';
|
||||||
|
import { BindleService } from './bindle.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class FocoCoffeeService {
|
||||||
|
constructor(
|
||||||
|
private readonly limaService: LimaService,
|
||||||
|
private readonly harbingerService: HarbingerService,
|
||||||
|
private readonly bindleService: BindleService
|
||||||
|
) { }
|
||||||
|
|
||||||
|
public async getAllProducts() {
|
||||||
|
const limaProducts = await this.limaService.fetchProducts()
|
||||||
|
const harbingerProducts = await this.harbingerService.fetchProducts()
|
||||||
|
const bindleProducts = await this.bindleService.fetchProducts()
|
||||||
|
return {
|
||||||
|
lima: limaProducts,
|
||||||
|
harbinger: harbingerProducts,
|
||||||
|
bindle: bindleProducts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getBeans() {
|
||||||
|
const limaBeans = await this.limaService.fetchProducts()
|
||||||
|
const harbingerBeans = await this.harbingerService.fetchProducts()
|
||||||
|
const bindleBeans = await this.bindleService.fetchProducts()
|
||||||
|
return {
|
||||||
|
lima: limaBeans
|
||||||
|
.filter(p => p.tags.includes("Coffee"))
|
||||||
|
.filter(p => !p.title.toLocaleLowerCase().includes("subscription"))
|
||||||
|
.filter(p => p.handle !== "lima-sample-pack")
|
||||||
|
,
|
||||||
|
harbinger: harbingerBeans.filter(p => p.product_type === "Packaged Coffee"),
|
||||||
|
bindle: bindleBeans.filter(p => p.product_type === "Coffee, Roasted")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
src/fococoffee/harbinger.service.ts
Normal file
16
src/fococoffee/harbinger.service.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { ShopifyProduct, parseShopifyProduct } from './shopifyUtils';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class HarbingerService {
|
||||||
|
public readonly shopifyUrl = 'https://harbingercoffee.com/products.json'
|
||||||
|
|
||||||
|
public async fetchProducts(): Promise<ShopifyProduct<Date>[]> {
|
||||||
|
const response = await axios.get(this.shopifyUrl)
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error('Failed to fetch products')
|
||||||
|
}
|
||||||
|
return response.data.products.map(parseShopifyProduct);
|
||||||
|
}
|
||||||
|
}
|
16
src/fococoffee/lima.service.ts
Normal file
16
src/fococoffee/lima.service.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { ShopifyProduct, parseShopifyProduct } from './shopifyUtils';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class LimaService {
|
||||||
|
public readonly shopifyUrl = 'https://www.limacoffeeroasters.com/products.json'
|
||||||
|
|
||||||
|
public async fetchProducts(): Promise<ShopifyProduct<Date>[]> {
|
||||||
|
const response = await axios.get(this.shopifyUrl)
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw new Error('Failed to fetch products')
|
||||||
|
}
|
||||||
|
return response.data.products.map(parseShopifyProduct);
|
||||||
|
}
|
||||||
|
}
|
74
src/fococoffee/shopifyUtils.ts
Normal file
74
src/fococoffee/shopifyUtils.ts
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
import { pipe } from "ramda";
|
||||||
|
|
||||||
|
export interface ShopifyVariant<T> {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
price: string;
|
||||||
|
sku: string;
|
||||||
|
position: number;
|
||||||
|
option1?: string;
|
||||||
|
option2?: string;
|
||||||
|
option3?: string;
|
||||||
|
taxable: boolean;
|
||||||
|
grams: number;
|
||||||
|
available: boolean;
|
||||||
|
created_at: T;
|
||||||
|
updated_at: T;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ShopifyImage<T> {
|
||||||
|
id: number;
|
||||||
|
created_at: T;
|
||||||
|
position: number;
|
||||||
|
updated_at: T;
|
||||||
|
product_id: number;
|
||||||
|
variant_ids: number[];
|
||||||
|
src: string;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ShopifyOption {
|
||||||
|
name: string;
|
||||||
|
position: number;
|
||||||
|
values: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ShopifyProduct<T> {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
handle: string;
|
||||||
|
body_html: string;
|
||||||
|
published_at: T;
|
||||||
|
created_at: T;
|
||||||
|
vendor: string;
|
||||||
|
product_type: string;
|
||||||
|
updated_at: T;
|
||||||
|
tags: string[];
|
||||||
|
variants: ShopifyVariant<T>[];
|
||||||
|
images: ShopifyImage<T>[];
|
||||||
|
options: ShopifyOption[];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const parseShopifyProductDates = (productIn: ShopifyProduct<string | Date>): ShopifyProduct<Date> => {
|
||||||
|
return {
|
||||||
|
...productIn,
|
||||||
|
published_at: new Date(productIn.published_at),
|
||||||
|
created_at: new Date(productIn.created_at),
|
||||||
|
updated_at: new Date(productIn.updated_at),
|
||||||
|
variants: productIn.variants.map((variant) => ({
|
||||||
|
...variant,
|
||||||
|
created_at: new Date(variant.created_at),
|
||||||
|
updated_at: new Date(variant.updated_at),
|
||||||
|
})),
|
||||||
|
images: productIn.images.map((image) => ({
|
||||||
|
...image,
|
||||||
|
created_at: new Date(image.created_at),
|
||||||
|
updated_at: new Date(image.updated_at),
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const parseShopifyProduct = pipe(parseShopifyProductDates);
|
Reference in New Issue
Block a user