GraphQL.Net List of int as argument - graphql-dotnet

I am trying to build an application using .Net and GraphQL. I need to get materials. not all of them but with the given Ids. When I pass it via playground or client side, I don't have any problem when I debug but I am not sure how to parse in the server side.
name: "materialsByIds",
arguments: new QueryArguments(
new QueryArgument<ListGraphType<IntGraphType>> { Name = "ids"}),
resolve: async (context) =>
{
var ids = context.GetArgument<IntGraphType>("ids");
// Do some action to bring datas
// Send data back
}
What am I missing here is there any methods to parse this in to list of int back?

Instead of using a GraphType for retrieving the argument, use the .NET type you want.
name: "materialsByIds",
arguments: new QueryArguments(
new QueryArgument<ListGraphType<IntGraphType>> { Name = "ids"}),
resolve: async (context) =>
{
var ids = context.GetArgument<List<int>>("ids");
// Do some action to bring datas
// Send data back
}

you can use MediatR. Create a Query class and pass it to mediateR. In CQRS, Command is used to write on DB(Create/Delete/Update of CRUD) and Query is used to read from DB(Read of CRUD).
create 'GetMaterialsByIdsQuery' and inside it write your code to get your materials by Id. then use it inside 'resolve' like this:
resolve: async context =>
{
var ids = context.GetArgument<List<int>>("ids");
return await mediator.Send(new GetMaterialsByIdsQuery(ids));
})
another way is that you can return somthing like MaterialsRepository.GetMaterialsByIds(ids) instead of using mediatR. But it is not recommended to use repository here. you can create a service class, inside it use your repository and then use your service here.

Related

Redux Toolkit Streaming updates - how to deal with relational entity adapters?

I am working on the chat that is utilising RTK Query with entity adapters.
I currently have 2 different entity adapters; one for chat and one for messages.
How can I go about selecting all messages for a specific chat? Do I need to store array of message ids inside of the chat adapter or do I select all messages and filter them by parent_chat_uuid property?
What is more efficient way to approach this? Is there a built in selector that allows you to select entities by its property rather then the id? I imagine mapping over extremely large array to find object with certain property is pretty expensive.
Thanks
edit:
I am initially querying latest chats and once cacheDataLoaded I add many chats to entity adapter.
I also setup websocket connection and subscribe to 'message' event after data is loaded. Everytime message is notified by ws I addOne message. If status like 'delivered' or 'read' is notified I would call updateOne.
I am actually trying to rewrite project that was not-using RTK Query and entity adapters and messages were always added to the messages array inside of the chat object. Websocket connection and updates were handle by middleware that was calling async thunks -> updating store.
I am trying move all the middleware to be handle inside of the rtk queries / mutation logic and call actions from there directly (or thunks with more logic that call actions).
**off topic and I can create a separate post for this but is there any benefit in creating a App Thunk (not async) that just calls an action? Should I just call actions instead in this case?
I'm an RTK maintainer, and "author" of createEntityAdapter (technically I ported it from NgRX, but I did a lot of work on it).
I actually did something like this myself on a previous project. I'd put a simplified version of the code into a gist, but I'll post it here for posterity too.
The technique that I used was nested entity adapters: a top-level one that stores chat rooms, and a nested one inside each room entry that stores that room's messages:
// Example of using multiple / nested `createEntityAdapter` calls within a single Redux Toolkit slice
interface Message {
id: string;
roomId: string;
text: string;
timestamp: string;
username: string;
}
interface ChatRoomEntry {
id: string;
messages: EntityState<Message>;
}
const roomsAdapter = createEntityAdapter<ChatRoomEntry>();
const messagesAdapter = createEntityAdapter<Message>();
const fetchRooms = createAsyncThunk(
"chats/fetchRooms",
chatsAPI.fetchRooms
);
const fetchMessages = createAsyncThunk(
"chats/fetchMessages",
async (roomId) => {
return chatsAPI.fetchMessages(roomId);
}
)
const chatSlice = createSlice({
name: "chats",
initialState: roomsAdapter.getInitialState(),
reducers: {
},
extraReducers: builder => {
builder.addCase(fetchRooms.fulfilled, (state, action) => {
const roomEntries = action.payload.map(room => {
return {id: room.id, messages: messagesAdapter.getInitialState()};
});
roomsAdapter.setAll(state, roomEntries);
})
.addCase(fetchMessages.fulfilled, (state, action) => {
const roomId = action.meta.arg;
const roomEntry = state.entities[roomId];
if (roomEntry) {
messagesAdapter.setAll(roomEntry.messages, action.payload);
}
})
}
})
/*
Resulting state:
{
ids: ["chatRoom1"],
entities: {
chatRoom1: {
id: "chatRoom1",
messages: {
ids: ["message1", "message2"],
entities: {
message1: {id: "message1", text: "hello"},
message2: {id: "message2", text: "yo"},
}
}
}
}
}
*/
That said, your situation sounds somewhat different, because you specifically said you're using RTK Query and trying to stream something. Because of that, I'm actually not sure how you're trying to set up the endpoints and store the data atm. If you can edit your post with more details and then leave a comment, I can try to update this response to give more advice.
Per the last question specifically: no, there's no built-in selectors for searching by properties, and doing that does generally turn into "re-filter all the items any time there's an update".

Loopback 4: Test problems with Sinon and injections

We have trying to do a test with loopback. The test involve to call the google API and we want to mock it with Sinon.
The Controller:
[...]
In the constructor:
#inject('services.OAuth2Service')
private oauth2Service: OAuth2Service
[...]
In the endpoint:
#post('/user-accounts/authenticate/oauth2', {
async authenticateOauth2(
#requestBody() oauthRequest: OAuthId,
#inject(RestBindings.Http.REQUEST) _req: Request,
): Promise<AccessToken> {
const email = await this.oauth2Service.getOAuth2User(oauthRequest); // The method to mock.
....
}
The test:
it('oauth2 authentication with google', async () => {
//Create a spy for the getOAuth2User function
inject.getter('services.OAuth2Service');
var oauth2Service: OAuth2Service;
var setOauthSpy = sinon.spy(oauth2Service, "getOAuth2User"); // Error: Variable 'oauth2Service' is used before being assigned
const res = await client
.post('/user-accounts/authenticate/oauth2')
.set('urlTenant', TEST_TENANT_URL1A)
.set('userType', TEST_USERTYPE1)
.send({
code: TEST_GOOGLE_AUTH2_CODE_KO,
providerId: TEST_GOOGLE_PROVIDER,
redirectUri: TEST_GOOGLE_REDIRECT_URI,
})
.expect(401);
expect(res.body.error.message).to.equal('The credentials are not correct.');
setOauthSpy.restore();
});
How can we test this method? how can we test an endpoint who involves an injection in the constructor in loopback? Please, we need any help.
I see two options:
Before running the test, create a loopback context, bind your stub to "services.OAuth2Service" and use that context to create the controller you want to test.
default value (probably not what you want)
In the place where you use #inject, you provide a default value (and possibly indicate the dependency is optional), e.g. like this:
#inject('services.OAuth2Service', { optional: true })
private oauth2Service: OAuth2Service = mockOAuth2Service,
In other places this might come handy for you, but you should probably not pollute your default production code with defaults to test objects.

Why POST using a 'Form' vs using a 'Body'?

The title expresses my post succinctly. Though the following side-note expresses my specific situation which sparked the question.
*Side Note: I'm making a web app with an Angular Front-end. I've found that once I encapsulate my data in a 'FormData' object from an
html form template, I am then unable to get those values back from
within client-side Angular (as posts like this one state:
How do i get the content from a formData?
). Though when I POST to ASP.Net with a '[FromForm]' attribute the
values get mapped fine.
So to make things easier I might rather acquire data from the form in
the first place and then use it in a 'body' POST instead of a 'form'
POST. Doing this so that I am passing around straight data I can work
with, instead of data wrapped in a form which I'm unable to work with
client-side.
So, thus, I'm wondering the differences between Posting 'forms' and
posting 'bodies', and whether there's any reason I should use one over
the other?
Update
In ASP.Net Core you can put attributes on your parameter types for REST endpoints. [FromForm] and [FromBody] are what I'm curious about. On the angular side, calling these REST endpoints requires passing either a 'FormData' (for the [FromForm]), or some sort of user defined type (for [FromBody]).
See below for examples.
Update
Here's the signature for the ASP.NET Endpoint for the '[FromBody]':
[HttpPost]
public async Task<IActionResult> CreateToken([FromBody] LoginViewModel model)
{...}
Here's the Angular snippet that calls this '[FromBody]' endpoint, along with the type that is passed in for the POST call:
public creds = {
username: "",
password: ""
}
login(creds): Observable<boolean> {
return this.http.post("api/account/createtoken", creds)
.pipe(
map((data: any) => {
this.token = data.token;
this.tokenExpiration = data.expiration;
this.username = data.username;
return true;
}));
}
Here is the signature for the ASP.NET Endpoint for the '[FromForm]':
[HttpPost]
public async Task<IActionResult> Signup([FromForm] SignupViewModel viewModel)
{...}
and here is the Angular snippet that calls this '[FromForm]' endpoint:
registerUser(formData: FormData) {
const options = {
headers: new HttpHeaders().set('Accept', 'application/json')
};
return this.http.post('api/account/signup', formData, options)
.pipe(
map(() => {
return true;
}),
catchError(this.handleError)
);
}
The FromForm attribute is for incoming data from a submitted form sent by the content type application/x-www-url-formencoded while the FromBody will parse the model the default way, which in most cases are sent by the content type application/json, from the request body

VueJS - How to make models and collections?

I am attempting to learn VueJS and I'm finding it hard to understand how to make models and collections.
For example, I want to have a collection (or list) of Employees and each Employee is a model.
But I'm not sure how to accomplish this in VueJS
Many thanks
Vue was initially created to bind data to a template in a reactive way, therefore, there's no "controller" or "model" notion like you would have in a regular MVC.
Vue just needs plain javascript objects as data, so if some of your data needs to be mapped to a model, well it's not about Vue, it's about... Javascript.
Here is an example of implementation (in ES6) :
class UserModel {
constructor(data) {
this.data = data
}
name() {
return this.data.firstname + ' ' + this.data.lastname
}
// and so on, put other methods here
}
var app = new Vue({
el: '#app',
data: {
user: {}
},
created() {
// axios or anything else for your ajax, or a new fetch api
axios.get('/me')
.then(response => {
// of course the "this" here is the Vue instance because i used an es6 arrow function
this.user = new UserModel(response.data)
})
}
})
That's it.
As you can see, Vue doesn't have to do with the Model class I created, I just mapped my ajax data to a custom class, then mapped the result to the Vue instance.
As simple as that.

Emberjs not accepting array from spring mvc properly

I am new to Ember and not very strong in JavaScript.
I am trying to use Java Spring MVC on a back-end with Ember on the front end. When I am trying to access a page. Ember makes a request for data to the server. Server answers with an Array, but the Array is not retrieved on the Ember side properly. I get an exception.
Error while loading route: Error: No model was found for '0'
at new Error (native)
at Error.Ember.Error (http://localhost:8080/libs/js/ember.js:844:19)
at Ember.Object.extend.modelFor (http://localhost:8080/libs/js/ember-data.js:9805:33)
at JSONSerializer.extend.extractArray (http://localhost:8080/libs/js/ember-data.js:3172:28)
at superWrapper (http://localhost:8080/libs/js/ember.js:1239:16)
at Ember.Object.extend.extractFindAll (http://localhost:8080/libs/js/ember-data.js:2380:21)
at Ember.Object.extend.extract (http://localhost:8080/libs/js/ember-data.js:2365:37)
at http://localhost:8080/libs/js/ember-data.js:10396:34
at invokeCallback (http://localhost:8080/libs/js/ember.js:9753:19)
at publish (http://localhost:8080/libs/js/ember.js:9423:9)
When debuging the javascript i found out that there is for in loop looping over an array
for (var prop in payload)
This for in loop is not retrieving the array elements, but is rather going throw properties. It might be because of what they talk about in this question on SO.
The - for me - problematic code is on github here.
Am I doing something wrong? should I report a bug?
I have created the following Ember model:
App.User = DS.Model.extend({
email: DS.attr('string'),
active: DS.attr('boolean'),
});
This is how the mapping looks like on server side
#RequestMapping("/users")
public
#ResponseBody
List<User> users() {
System.out.println("getting users");
List<User> list = new LinkedList<User>();
list.add(new User(1,"test#b.c"));
list.add(new User(2,"test2#b.c"));
list.add(new User(3,"test3#b.c"));
return list;
}
This JSON I got from fiddler:
[{"id":1,"email":"test#b.c","active":true},{"id":2,"email":"test2#b.c","active":false},{"id":3,"email":"test3#b.c","active":false}]
By default, I believe ember-data expects your JSON response to be prefixed with the model name, even if it's an array. This means you're data will need to be formatted like this:
{
"users":[
{
"id":1,
"email":"test#b.c",
"active":true
},
{
"id":2,
"email":"test2#b.c",
"active":false
},
{
"id":3,
"email":"test3#b.c",
"active":false
}
]
}

Resources