Generate Open API Spec from Model/Controller Metadata in Loopback4 - node.js

Does Loopback4 provide a way to generate an Open Api Spec from decorated models and controllers?
If not, is there a way to access controllers and models metadata at runtime?

Noticed just now that the server object exposes the getApiSpec method which returns an OpenApiSpec object.
export class MyController {
constructor(
#inject('application.instance') private app: Application,
#inject('rest.http.request') private req: ServerRequest) { }
#get('/spec')
async api(): Promise<OpenApiSpec> {
const server = await this.app.getServer(RestServer);
return server.getApiSpec();
}
}
EDIT: This solution doesn't solve the problem completely
The api spec returned by server.getApiSpec() doesn't contain information about the models.

After you started the LoopBack 4 application (assuming you did not change the REST server port), go to http://localhost:3000/openapi.json, you'll get the OpenAPI spec.

Related

What are the ways to expose GraphQL Schema as REST api?

I have Graphql api developed and want to expose few REST API endpoints from it. so here my intention is use same Graphql logic to expose it as rest api. So far I got posts about using sofa to achieve this and want to check if there is any NestJS or Graphql existing package which we can use.
It depends on how you've structured your application thus far. In general, NestJS promotes an N-tier architecture where business logic belongs inside of Services/Providers. When structured this way, it becomes relatively straightforward to share logic between GraphQL resolvers and HTTP controllers.
Resolvers and Controllers should act purely as routing components that receive requests/data and pass them to the appropriate service for processing.
#Resolver()
class MyResolver {
constructor(private readonly service: MyService) { }
#Query()
doSomething() {
return this.service.doSomething();
}
}
#Controller()
class MyController {
constructor(private readonly service: MyService) { }
#Get()
doSomething() {
return this.service.doSomething();
}
}
You have developed a GraphQL API , which you then want to expose as REST , or you want to integrate a REST API in your GraphQL API? If it's the first one , you are totally missing the point of GraphQL. If it's the second one , then you need to pass the context argument in your Apollo Server constructor , containing a dataSource argument. Then you have to define a class that extends RESTDataSource (https://www.apollographql.com/docs/apollo-server/data/data-sources/).

How to make a private call when using SSR Nuxt?

I am writing a headless solution for a WordPress website and noticed that for one particular endpoint, I need to authenticate to pull some data that will be used publicly. But, I'm concerned that where I'm using it will expose it to the web.
In my store/index.js I use the nuxtServerInit action method to execute some actions and I pass them some objects they need to fulfill their tasks:
async nuxtServerInit ({ dispatch }, { $axios, app }) {
await dispatch('initialize', { $axios, app })
},
$axios is passed because it will be used to query the API, and app is passed to help build the options to authenticate the request.
Is this a security vulnerability in Nuxt SSR? I think it is. If so, where are the only valid areas you can use secrets? asyncData ()?
If you're using SSR, you can use the privateRuntimeConfig runtime object and pass your secret in the nuxt.config.js file
export default {
privateRuntimeConfig: {
apiSecret: process.env.API_SECRET
}
}
If you read the documentation of nuxtServerInit, you can see that
Vuex action that is called only on server-side to pre-populate the store
Since this method is server-side only, you can use apiSecret (in my example) and it should be totally fine security-wise.
PS: Keep in mind that everything beyond what is generated on the server (hence, with NodeJS or nuxtServerInit) is "public". So your VueJS's client code lifecycle hooks are public: mounted(), fetch(), asyncData() because they will be visible on your browser's devtools.
Also, should your endpoint be that critical? If so, nuxtServerInit is the good way to go. If you need to fetch some more data in a "private way", you'll need to proxy it through some backend to hide the sensitive info and retrieve only the useful public data.

Attach user details to request object in nestjs

I set globally middleware to attach data to request object and it work in http...
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer): void {
consumer.apply(AuthMiddleware).forRoutes('*');
}
But it is not work in gateway(websocket)...
why this middleware that set on all routes not work in gateway(websocket)...?
or
what is the best way for attach authorized user to request in http and websocket...?
You've got the answer from creator of the framework. Just in case someone is facing the same
Middleware don't apply to the websockets - it's not an issue. Use interceptor/guard instead.
https://github.com/nestjs/nest/issues/1634#issuecomment-472553863

Using mobx-model in the server

I am using Mobx and mobx-model for state management in my React app. I am not doing server-side render as of now. But, I have a scenario where I need to use my model in the server side.
An example model in my project is shown below.
import { API, BaseModel } from "mobx-model";
class UserModel extends BaseModel {
...
static loadAll() {
...
}
}
The above model works fine in the client (in the browser). But, I have a scenario where I need to call the loadAll method from the server.
If I require this model from the server side as follows, I get an error.
const { UserModel } = require("../../src/models/models");
The error message is:
SyntaxError: Unexpected token import
Any idea how I can fix this to work on the server side?
I found a solution to this problem. Instead of requiring the UserModel, I could require the API from mobx-model as follows:
const { API } = require("mobx-model");
I could use the API from the server without much code changes. I have to rewrite a little bit of loadAll logic again in the server. That works for me for now.

Sails call one controller from another controller

I am having two controllers, SocketController and ProjectController
SocketController has method getData(data)
ProjectController has method addProject(data)
I need to call addProject() from getData() method.
I tried using sails.controllers.ProjectController.addProject(data) but I got following error:
Cannot find method addProject of undefined
I searched for alternative ways to call another controller using services in Stack Overflow but that was of no help to me. Is there any other way to get this work?
Controllers are just Node modules that export public methods. You can require them like anything else. So assuming your methods are correctly exposed with module.exports, this will work:
/* ProjectController */
module.exports = {
addProject: function(data) {
// ...
}
};
/* SocketController */
// Assuming ProjectController.js exists in the same directory (default for Sails)
var projectController = require('./ProjectController');
module.exports = {
index: function(req, res) {
// ...
projectController.addProject(...);
}
};
Edit: I will add that using services is a better place to keep common functionality like your example. Services allow complex logic to be decoupled from the controller layer and reused by other areas of the application with ease. Controllers should generally be reserved for handling HTTP requests from the client and passing the data to the service or model layers for manipulating the database. I believe Sails also makes services global by default so you don't have to worry about confusing require paths.
Controller functions are also accessible through the global sails object, without use of require, however a function from ProjectController will be found under:
sails.controllers.project.addProject
instead of
sails.controllers.ProjectController.addProject
Anyways you might want to consider having shared functionality in either services or models, as was pointed out previously.

Resources