Apollo GraphQL: Augment instead of overriding default resolver behaviour - javascript

In the Apollo Server documentation, it describes the behaviour of the default resolver, which is quite handy.
I also gathered from somewhere else (another SO question if I recall), that you can override the default resolver function with your own, by passing a fieldResolver function into the options for the apollo-server instance:
const server = new ApolloServer({ typeDefs, resolvers,
fieldResolver: function (source, args, context, info) {
console.log("Field resolver triggered!")
return null;
}
});
What I would like to do is augment the default behaviour, rather than overriding it. Specifically, I am integrating with a REST API that returns fields in snake_case, whereas my schema is attempting to follow the advised convention of using camelCase for field names. I would like to wrap this field name conversion around the default resolver behaviour, rather than having to re-write it.
Alternatively, if somebody can point me to the source location for the default resolver implementation, I'd be happy enough to take that and adapt it either!

The default resolver is available through the graphql module:
const { defaultFieldResolver } = require('graphql')
However, converting a field from snake case to camel case can be done without calling the default resolver:
someField: (parent) => parent.some_field
If you want to create a reusable resolver function, you can do something like:
const camelCaseResolver = (parent, args, ctx, info) => {
return parent[_.snakeCase(info.fieldName)]
}
Or better yet, extract the logic into a schema directive:
class SnakeCaseDirective extends SchemaDirectiveVisitor {
visitFieldDefinition(field) {
field.resolve = async function (parent, args, ctx, info) {
return parent[_.snakeCase(info.fieldName)]
}
}
}

Related

Private methods in React service function component

I'm a bit new to React and I'm currently developing a Proyect which has a service layer. To do so, I created a function component which would have the methods as variables:
const CustomComponent = () => {
method1 = () => {...},
method2 = () => {...},
method3 = () => {...}
}
export default CustomComponent;
This component would then be imported to the component that will use it.
To make my architecture as clean as possible, I wanted to make some of the methods private. However, as you may already know, that is not possible to do in the solution I proposed. Do hoy have an idea on how to achieve this, or maybe there is a convention to make a service layer I'm not aware of?
Thank you so much in advance!
The architecture which I find particularly clean and maintainable is one where you split off logic from presentation into two files like this:
Service layer (ts):
export class Service implements ServiceInterface {
constructor(private instanceVariable: string = "foo") { }
private methodOne(): string {
return this.instanceVariable
}
public methodTwo(argumentVariable: string): string {
const importantString = this.methodOne();
return importantString + argumentVariable;
}
}
interface ServiceInterface {
methodTwo(argumentVariable: string): string;
}
export default new Service();
Service layer (js):
export class Service {
instanceVariable;
constructor(contructorArgument) {
this.instanceVariable = contructorArgument;
}
methodOne() {
return this.instanceVariable
}
methodTwo(argumentVariable) {
const importantString = this.methodOne();
return importantString + argumentVariable;
}
}
export default new Service();
Presentation layer:
import Service from "./service.ts";
const FunctionalComponent = () => {
const [localState, setLocalState] = useState(localStateInit);
return (
<>
<div>{Service.methodTwo("bar")}</div>
</>
)
}
Few things happen here (mostly regarding ts implementation).
Keep component's service and presentation layers in separate files.
Use an interface to describe the service class and its methods. This will help to work with your service layer in your component as you'll get Typescript's IntelliSense.
For this example I'm exporting an instance of the service as default export from its file. This gives you a cleaner API in your component's file, where you can call methods without having to "pollute" component file with instance creation. This has at least the following two drawbacks:
you mostly lose ability to work nicely with static class members
preconfigured instance variable (initiated as a private member in constructor) means its value cannot be replaced in testing.
If any of above are a no go, then clean up the constructor, export just the class itself and instantiate it as required in component file.
I'm also exporting the class itself. This is for testing purposes. In testing you want to be able to swap out arguments passed into class' constructor and you need to have class definition to do that.
You'll notice the shorthand notation for declaring and instantiating a private class variable in the constructor: private instanceVariable: string = "foo". This is equivalent to something like this:
class Service {
private instanceVariable: string;
constructor(constructorArgument: string) {
this.instanceVariable = constructorArgument;
}
Such notation is particularly nice when used with dependency injection.
Overall, this setup will help you with unit testing logic in your service layer, as you can test it like any other class. This comes particularly handy when there's a lot of conditional rendering logic.
Let me know if this is what you've been looking for. Maybe we could tailor it better for your use case.

Apply JWT Guard for an endpoint but do not apply it when it has a request parameter

Is there a way to use if conditions when applying #UseGuards(JwtAuthGuard) rule for an endpoint in controller?
#UseGuards(JwtAuthGuard)
#Get("/foo/:bar?")
async get(#Param() param: RequestParamDto)
Having an endpoint /foo should require JWT Authorization token when calling it (which it does with the code above), but when we are passing something in a request parameter e.g. /foo/bar it should turn off a guard.
I don't see a way to apply if-else conditions when applying Guards on a Controller level.
You can apply if-else conditions in guards. Not at the controller level though, but you can achieve your desired condition following the next steps:
First of all, define a new decorator with the following code:
import { SetMetadata } from '#nestjs/common';
export const IS_PUBLIC_KEY = 'isPublic';
export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
With this code, you are going to define a new decorator by the name #Public(). And link the IS_PUBLIC_KEY to the value true which in turn will be linked to the decorator. The purpose of its existence is to enable the guard to identify which routes do you desire to be accessed by everyone.
The next step would be to add the decorator to the desired route:
#UseGuards(JwtAuthGuard)
#Get("/foo/:bar")
#Public()
async get(#Param() param: RequestParamDto)
Finally, in the JwtAuthGuard class you should have the following code:
#Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
constructor(private reflector: Reflector) {
super();
}
canActivate(context: ExecutionContext) {
const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
context.getHandler(),
context.getClass(),
]);
if (isPublic) {
return true;
}
return super.canActivate(context);
}
}
In the code inside the canActivate function, you are now using the reflector property of NestJs to fetch the constant IS_PUBLIC_KEY added to the custom decorator. Thus, the guard will be able to tell when you want the route to be public for everyone to access.
If you want further information on this issue, refer to the official documentation here.

Pattern for redirecting on unauthorized vuex actions

Navigation guards are perfect for redirecting unauthorized users to a login page, but what does one do to redirect unauthorized vuex actions to a login page?
I can do this easily enough in the vue method where I'm calling the action like so:
if (!this.isLoggedIn) {
this.$router.push({ name: 'login', query: { comeBack: true } })
$(`.modal`).modal('hide')
return
}
But then I'm inserting these 5 lines of code for every component method that requires authorization.
All the solutions I can think of sound hacky, so I'm wondering what the vuex way is:
In order to reject it at the vuex action level, I have to pass up the $router instance, and I'm still reusing the 5 lines for each action that requires auth.
I can handle this in a utility file, but then I'm handling $router instance in that file.
I can use a global vue mixin and call it (a) before making a call and then again (b) when getting a 401 back from the server.
All those seem odd. What vuex way am I missing here?
This sounds like a job for middleware. Unfortunately, Vuex doesn't have an official way to do middleware.
There is a subscribeAction() but that runs after the commit, so does not allow mods to the action. There is also a proposal Middleware processing between actions and mutation.
As I see it, we want middleware to be able to do two generic things
cancel the action
allow alternative actions to be called
The second is difficult to do without patching store.dispatch() or messing with the private property _actions after store has been created.
However, to guard an action as you describe, we only need to be able to cancel it.
Here is a poor-man's middleware for the modules pattern for Vuex store which I prefer.
store construction from modules
export const store = new Vuex.Store({
modules: {
config,
pages: applyMiddleware(pages),
measures,
user,
loadStatus,
search
}
})
applyMiddleware
const applyMiddleware = function(module) {
if(module.middlewares) {
Object.values(module.middlewares).forEach(middlewareFn => {
Object.keys(module.actions).forEach(actionName => {
const actionFn = module.actions[actionName]
module.actions[actionName] = addMiddleware(actionName, actionFn, middlewareFn)
});
})
}
return module;
}
addMiddleware
const addMiddleware = function(actionName, actionFn, middlewareFn) {
return function(context, payload) {
const resultFn = middlewareFn(actionFn)
if(resultFn) {
resultFn(context, payload)
}
}
}
defining middleware in the module
const actions = {
myAction: (context, payload) => {
...
context.commit('THE_ACTION', payload)
...
},
}
const middlewares = {
checkAuthMiddleware: (action) => {
return this.isLoggedIn
? action // if logged-in run this action
: null; // otherwise cancel it
}
}
export default {
state,
getters,
mutations,
actions,
middlewares
}
This implementation has module-specific middleware functions, but you could also define them globally and apply to as many modules as applicable.

GraphQL - Syntax Error GraphQL request (5:15) Expected Name

I am trying to implement a graphQL API, it went well with queries but it's going not that well with mutations:
Here is my basic mutation using apollo-client and graphql-tag:
import gql from 'graphql-tag'
const addNewPlace = (place) => {
return client.mutate({
mutation: gql`
mutation {
addNewPlace(
input: {
$title: String!
}
) {
place { title }
}
}
`,
variables: {
title: place.title
}
})
}
Here I was trying to use variables. When changing the mutation to look like that one below, it is going smoothly however, it's not the right way to do id.
const addNewPlace = (place) => {
return client.mutate({
mutation: gql`
mutation {
addNewPlace(
input: {
title: "${place.title}"
}
) {
place { title }
}
}
`
})
}
Any idea where I made my mistake?
When using variables, there's three steps you need to take:
Add the variables to the request being sent. In Apollo, it's done by specifying a variables property inside the object you pass to mutate. You wrote:
variables: { title: place.title }
This is fine. We are sending some variable, called title, with whatever value, along with the request to our server. At this point, GraphQL doesn't even know about the variables.
Declare your variables inside your operation. You don't have to name your operation, but it's good practice to do so:
mutation AddNewPlace($title: String) {
Here, we are telling GraphQL we've included a variable called title. You could call it anything (foo for example), as long as it matched what you passed to the variables prop in #1. This step is important because A) GraphQL needs to know about the variable and B) it needs to know what type of variable you are passing in.
Finally, include the variable in your mutation, like this:
addNewPlace(input: { title: $title }) {
Be careful not to mix up your variable definition in step #2 with your input definition in step #3. Also, I'm assuming your typeDefs include some kind of input type like AddNewPlaceInput. Rather than passing in just title, you can pass in an object like this:
variables: { input: { title: place.title } }
Then your mutation looks like this:
mutation AddNewPlace($input: AddNewPlaceInput) {
addNewPlace(input: $input) {
# fields returned by the mutation
I would highly recommend enabling a GraphiQL endpoint so you can easily test your queries and mutations before implementing them on the client side.
Lastly, you may want to check and make sure the fields you are asking for in the mutation match your type definition. I'm just guessing here, but if your mutation resolves to a Place type, you wouldn't need to put place { title }, just title, unless your Place type actually has a place field.

Electron: Use same singleton in main and renderer

I'm attempting to create a singleton class that works in both the main and renderer processes, but I'm not sure what the best way of going about it is.
For example, I have a class which handles storing data:
class Prefs {
constructor() {
this.prefsCache = // Load the prefs from a json file into the cache
}
set(key, value) {
this.prefsCache[key] = value
// Also save the prefs to disk here
}
get(key) {
return this.prefsCache[key]
}
}
export default new Prefs()
This works great in a single process, but if the class is required in the main and renderer, the cache will become out of sync the minuet a preference is changed since each process has a different instance.
It looks like the solution is to use IPC, but I can't find an elegant solution for it. Here I create two different classes. PrefsMain handles saving and storing the data, and PrefsRenderer would communicate to the PrefsMain:
class PrefsMain {
constructor() {
ipcMain.on('set-prefs-value', (event, key, newValue) => {
this.set(key, newValue)
})
}
set(key, value) {
// ...
}
}
class PrefsRenderer {
set(key, newValue) {
ipcRenderer.sendSync('set-prefs-value', key, newValue)
}
}
Doing something like above works, but in reality, I have multiple singletons each with 20 or so methods. It seems like a lot of extra code needs to get written to accomplish it this way.
The other solution I found was to use electron's remote module:
const Prefs = require('electron').remote.require('./prefs.js')
This also works, but it looks like the remote module is going to be deprecated, so I'd rather not do it this way.
Is there a better solution for this? How can I elegantly create a singleton class that can be used in both the main and renderer processes, without having to create a duplicate IPC handler class for each?
You don't need to create two separate classes.
Just have a single Prefs class.
And then for your renderer to set or get things from the Prefs singleton, you would add ipc handlers to your main process:
ipcMain.on("setIntoPrefs", (event, key, value) => {
prefsInstance.set(key, value);
});
ipcMain.handle("getPrefsValue", (event, key) => prefsInstance.get(key));
And your renderer would do:
ipcRenderer.send("setIntoPrefs", key, val);
const val = await ipcRenderer.invoke("getPrefsValue", key);

Categories