remix fetch data within a loader from another loader - remix.run

Trying to fetch data internally within remix application
from an api route located in
/routes/api/test.tsx
export const loader = async ({ request }: LoaderArgs) => {
const testRes = await fetch("/api/test");
return await testRes.json();
};
I get error Invalid URL
what is the right convention for this?

If you want to call another URL you have to pass in the full url. Something like:
export const loader = async ({ request }: LoaderArgs) => {
const testRes = await fetch("https://example.com/api/test");
return await testRes.json();
};
To have the domain be dynamically set you could use the URL from the request. Something like this:
export const loader = async ({ request }: LoaderArgs) => {
const domain = new URL(request.url).hostname;
const testRes = await fetch(`${domain}/api/test`);
return await testRes.json();
};

Related

How to use async callback to determine resource to cache in workbox precacheAndRoute

In my service worker, I'm making use of workbox's precacheAndRoute from workbox-precaching. I want to cache files paths that already exist on IndexedDB since it varies across users. My code looks like this:
import { precacheAndRoute } from 'workbox-precaching';
import localforage from "localforage";
let formID;
const cachedFilesStore = localforage.createInstance({
name: 'page-id',
storeName: 'store'
})
const produceValuesFromCache = () => {
return cachedFilesStore.getItem('1')
.then(async (value) => {
formID = formID || value.form_id;
const cachedFiles = await cachedFilesStore.getItem(`${formID}`)
return [
...cachedFiles.manifest,
`/form/${formID}`
]
});
}
precacheAndRoute([], {
urlManipulation: async ({ url }) => {
const files = await produceValuesFromCache();
return files
}
})
It doesn't work as expected, instead I see an error like so: Uncaught TypeError: additionalURLs is not iterable. What am I doing wrong?
The code that dumps the files in IndexedDB is in the index.html file which is located at route form/${formID.

How to test dispatched react function using Jest

I am trying to unit test a function which makes an async call using an Axios helper instance. I have attempted multiple ways of trying to unit test this but I can not seem to find any material online which has helped. I've been stuck on this problem for a few days which is frustrating so any help would be appreciated! Below are the Axios Helper file (api.js)
api.js
import axios from 'axios'
const API = (token = null) => {
let headers = {
'Content-Type': 'application/json',
'Ocp-Apim-Subscription-key': process.env.NEXT_PUBLIC_API_HEADER_SUBSCRIPTION_KEY
}
if (token) {
const tokenHeader = { Authorization: 'Bearer ' + token }
headers = { ...headers, ...tokenHeader }
}
const url = process.env.NEXT_PUBLIC_API_BASE_URL
const API = axios.create({
baseURL: url,
headers
})
return API
}
export default API
mocked API
export default {
post: jest.fn(() =>
Promise.resolve({
data: {}
})
),
get: jest.fn(() =>
Promise.resolve({
data: {}
})
)
}
action file
export const initiate2FA = (destinationValue) => async () => {
const twoFactorAuth = destinationValue
const res = await API().post('/foo', {
Destination: twoFactorAuth
})
return res
}
Action.test.js
import API from 'api/api'
import { initiate2FA } from 'actions/userActions'
jest.mock('api/api')
const mockedAxios = API
const dispatch = jest.fn()
describe('Initiate2FA function', () => {
it('bar', async () => {
mockedAxios.get.mockImplementationOnce(() => Promise.resolve({ status: 200 }))
const t = await dispatch(initiate2FA('test#test.com'))
console.log(t)
})
})
My issue with the above test file is that it returns an anonymous function and I do not know how to handle this to pass the unit test. The goal of the test is to make sure the function is called. I am not sure if I am approaching this the correct way or should change my approach.
Again, any suggestions would be great!
Mocking an API call is something you can mock on your own React component, instead of a function, and the best option would be to not mock anything on your component. Here you can read all about why you should not mock your API functions. At the end of the article, you're going to find a library called Mock Service Worker which you can use for your purpose.
The way you declare you have an actual HTTP called that needs to be mocked would be something like this:
rest.get('/foo', async (req, res, ctx) => {
const mockedResponse = {bar: ''};
return res(ctx.json(mockedResponse))
}),
If you just need to unit test a function, you can still use Mock Service Worker to resolve the HTTP request, and then test what happens after that. This would still be your first choice. And the test would look like:
// this could be in another file or on top of your tests.
rest.get('/foo', async (req, res, ctx) => {
const mockedResponse = {bar: ''};
return res(ctx.json(mockedResponse))
}),
// and this would be your test
describe('Initiate2FA function', () => {
it('bar', async () => {
const res = await initiate2FA('test#test.com');
expect(res).toBe({bar: '');
})
})

How to access privateRuntimeConfig declared in Nuxt.config.js in serverMiddleware?

How to access configuration declared in privateRuntimeConfig in Nuxt.config.js file in serverMiddleware?
$config and context are not available in serverMiddleware.
I am using serverMiddleware in Nuxtjs to write api.
Its getting called however I am trying to pass some configuration from privateRuntimeConfig in Nuxt.config.js file.
const bodyParser = require('body-parser')
const app = require('express')()
const { uuid } = require('vue-uuid')
const productsModule = require('../lib/bal/products')
app.use(bodyParser.json())
app.post('/create', (req, res) => {
console.log('Config:' + String(req))
const result = productsModule.createProduct(this.$config, req.body.name, 'Trial product', '', 10, false, uuid.v1)
if (result === undefined) {
res.status(500).json({ error: 'Failed to create product. Try again!' })
return
}
console.log(result)
res.status(200).json(result)
})
module.exports = app
Yes you are right, since serverMiddleware only runs at service-side you can't use this.$config or context.$config.
What i did is, if it is a static data, i use environment variables to call the data.
.env file
APP_USERNAME=M457ERCH1EF
serverMiddleware file i.e xxx.js
....
const username = process.env.APP_USERNAME
....

POST request with parameters doesn't work with koa-router

I'm trying to build a simple REST API with Koa. For this, I am using koa-router. I have two problems:
Whenever I try to add parameters to my POST-Method in mainRouter.ts like ":id", Postman shows a "not found". My request: http://localhost:3000/posttest?id=200
I cannot get the parameters with "ctx.params". I also can't find anything about it on the koajs-page, but I do see examples like this everywhere?!
This is my app:
app.ts
import * as Koa from 'koa';
import * as mainRouter from './routing/mainRouter';
const app: Koa = new Koa();
app
.use(mainRouter.routes())
.use(mainRouter.allowedMethods());
app.listen(3000);
mainRouter.ts
import * as Router from 'koa-router';
const router: Router = new Router();
router
.get('/', async (ctx, next) => {
ctx.body = 'hello world';
});
router
.post('/posttest/:id', async (ctx, next) => {
ctx.body = ctx.params.id;
});
export = router;
If I change the POST-method to this, then I get "200":
router
.post('/posttest', async (ctx, next) => {
ctx.body = ctx.query.id;
});
If you're using a query string in your request like this:
http://localhost:3000/posttest?id=200
Then your route handler should be using ctx.query, not ctx.params:
router.post('/posttest', async (ctx, next) => {
console.log(ctx.query.id); // 200
});
You should only use ctx.params when you want to send requests like this:
http://localhost:3000/posttest/200
In which case you would write the route handler like so:
router.post('/posttest/:id', async (ctx, next) => {
console.log(ctx.params.id); // 200
});

REST API with koa2. Common prefix for several routers

I have two entities, users and employees. So I want CRUD for both in different endpoints, but both of them will be mounted under "api", so I can define api_v1, api_v2 and so on.
The endpoints would be something like:
get api/users
put api/users/12
delete api/users/12
get api/employees
....
I can't get "api" prefix for both of my routes. Can't get it working with koa-mount.
My files:
server.js
// Dependencies
import Koa from 'koa'
import mongoose from 'mongoose'
import logger from 'koa-logger'
// import parser from 'koa-bodyparser';
import convert from 'koa-convert'
import serve from 'koa-static'
import Router from 'koa-router'
import session from 'koa-generic-session'
import mount from 'koa-mount'
// A seperate file with my routes.
import routingUsers from './users'
import routingEmployees from './employees'
// config
const config = require("./config/config")
// connect to the database
mongoose.connect(config.mongo.url)
mongoose.connection.on('error', console.error)
// Creates the application.
const app = new Koa()
// how to use koa-mount to make this work? Arghhhhh!
// const api = new Koa();
// api.use(convert(mount ('/api', app)))
// trust proxy
app.proxy = true
// sessions
app.keys = ['your-session-secret']
// Applies all routes to the router.
const user = routingUsers(Router())
const employee = routingEmployees(Router())
app
.use(logger()) // log requests, should be at the beginning
.use(user.routes()) // asign routes
.use(employee.routes()) // asign routes
.use(user.allowedMethods())
.use(employee.allowedMethods())
.use(convert(session())) // session not needed for an API??????
.use(convert(serve(__dirname + '/public'))) // for static files like images
// Start the application.
app.listen(3000, () => console.log('server started 3000'))
export default app
users.js (employees.js is the same).
// Export a function that takes the router
export default router => {
// Set a prefix of our api, in this case locations
const api = 'users'
router.prefix(`/${api}`);
// GET to all locations.
router.get('/', (ctx, next) =>
ctx.body = 'hello users');
// ctx.body = await Location.find());
// POST a new location.
router.post('/', async (ctx, next) =>
ctx.body = await new Location(ctx.request.body).save());
// Routes to /locations/id.
router.get('/:id', async (ctx, next) =>
ctx.body = await Location.findById(ctx.params.id));
// PUT to a single location.
router.put('/:id', async (ctx, next) =>
ctx.body = await Location.findByIdAndUpdate(ctx.params.id, ctx.body));
// DELETE to a single location.
router.delete('/:id', async (ctx, next) =>
ctx.body = await Location.findByIdAndRemove(ctx.params.id));
return router;
}
I use the following solution:
import Router from 'koa-router';
const router = new Router()
.get('/', function(ctx) {
ctx.body = 'Index';
});
const apiRouter = new Router({
prefix: '/api'
})
.get('/templates', Templates.index)
.post('/templates', Templates.store)
.put('/templates', Templates.update)
.get('/lists', Lists.index);
router.use(apiRouter.routes());
Finally I've sent another parameter to the routers modules, so I used router prefix:
// Applies all routes to the router.
const user = routingUsers(Router(), 'api/users/')
const employee = routingEmployees(Router(), 'api/employees/')
Users would be:
export default (router, prefix) => {
// Set a prefix of our api, in this case locations
// const api = 'users'
router.prefix(`/${prefix}`);
....

Resources