ReactJs Check Validity of HTTP Request Response - reactjs

I am wondering if there is a way to check if the response type is parsable into a specific type:
interface ExpectedResponse
{
anInteger: number;
aBoolean: bool;
aString: string;
}
function sendRequest() : Promise<ExpectedRespnse>
{
const response = await <HTTP call>
return response as ExpectedResponse;
}
In this example, if the response data can be mapped 1:1 to the interface, everything is fine. The object will be treated as an ExpectedResponse object when automatically deserialized.
Is there a way to ensure that the response data is ExpectedResponse with all required attributes filled and no "undefined" attributes not filled?

Related

how intercept and stub the response of a rpc call in react with cypress

I want to intercept a rpc call that I made to the api in my react app. I'm using a custom hook that receives the buffer and the rpc method that I want to call and returns the data(something like react-query useQuery hook).
The thing is because of being a rpc call, the request urls of my requests are all the same and the response is binary, I can't distinguish the requests and intercept the one to stub.
One example of making a rpc call:
const {response, loading, error} = useRpc({
Buffer: GetUser,
Request: GetUserRequest
});
Edit 1:
I'm using
cy.fixture('fixutre-file').then((data) => {
const response = new TextDecoder().decode(res.body);
cy.intercept('https://example.com/', { method: 'POST' },
(req) => {
req.continue((res) => {
if ("some condition for distinguishing the request I want to intercept, here") {
res.send({ fixture: 'fixutre-file' });
}
});
});
}):
to get the response and decide whether or not intercept this req and instead send back my fixture data. But the response constant is still some unreadable string. What's wrong with my approach?
Edit 2:
Another approach that I used, was to use the cypress-protobuf package and encode my fixture.json file with the related protobuffer file:
cy.fixture('fixutre-file').then((data) => {
cy.task('protobufEncode', {
fixtureBody: data,
message: 'the_message',
protoFilePath: './protobuf/protofile.proto'
}).then((encodedData) => {
cy.intercept('https://example.com/', { method: 'POST' },
(req) => {
/////// approach 1(didn't work): ///////
// can't use this approach(because there is no identifier on
// req object to distinguish the requests I want to
// intercept)
// if ("some condition based on `req` here") {
// req.reply(encodedData);
// } else {
// req.continue();
// }
/////// approach 2: ///////
// using encodedData to compare it with res.body
req.continue(res => {
// can't compare res.body with encodedData, because
// encodedData is an empty string!
});
}).as('needToWait');
cy.wait('#needToWait').get('some selector').should('exist')
});
}):
Now the problem is:
encodedData is just an empty string, meaning it didn't work, so I can't compare the response with my fixture data to intercept the related request
You can simply check for some value from the request that distinguishes it from the other requests. Request bodies and headers are often good places to start. Additionally, you can use req.alias to conditionally assign an alias if you need to wait for that specific call.
cy.intercept('/foo', (req) => {
if (req.body.bar === true) { // or whatever logic indicates the call you want to intercept
req.alias = 'baz'; // conditionally assign alias
req.reply({foo: 'bar'}); // mock response
} else {
req.continue(); // do not mock response
}
});
cy.get('something')
.click()
.wait('#baz'); // waits for your specific 'baz' call to happen.

How to upload images in react via api?

Today I saw a number of tutorials on how to upload photos in react via the api.
I did everything, tried all the methods. But in the end I get stuck.
(During the whole explanation I will focus only on the features of the image upload)
In Models I have groups and variable -
[NotMapped]
public IFormFile ImageFile {get; set; }
In api I get
[Route ("Add")]
[HttpPost]
public void Post (Group group)
And I have in state-
const initialFieldValues ​​= {
GroupName: '',
GroupAbout: '',
imageName: '',
imageSrc: defaultImageSrc,
imageFile: null
}
const [values, setValues] = useState (initialFieldValues)
When changing the image has a function-
const handleImg = (e) => {
if (e.target.files && e.target.files [0]) {
let imageFile = e.target.files [0];
const reader = new FileReader ();
reader.onload = x => {
setValues ​​({
... values,
imageFile,
imageSrc: x.target.result
})
}
reader.readAsDataURL (imageFile)
SetDisplayImg ("block");
}
else {
setValues ​​({
... values,
imageFile: null,
imageSrc: defaultImageSrc
})
}
};
And when submitting the form
const handleFormSubmit = e => {
e.preventDefault ()
const formData = new FormData ()
.append ('groupImage', values.imageFile)
addOrEdit (formData)
}
const addOrEdit = (formData) => {
axios.post ('api / groups / add', formData) .catch (error => {
console.log (error.response.data);
console.log (error.response.status);
console.log (error.response.headers);
});
}
In this code -makes error 415 (even regardless of uploading the image but, even if I put it only other variables that get stringed and work normally.)
If I add [FromForm] in the api it does not respond to me, i.e. it does not write me an error message nor does it reach the api (I checked in debugging)
If I change the axios to
const obj = {'groupImage': values.imageFile
}
axios.post ('api / groups / add', obj) .catch (error =>
I get an error message 400-
"The JSON value could not be converted to System.String. Path: $ .groupImage
And if I send the value from state
axios.post ('api / groups / add', values)
I get an error message System.NotSupportedException: Deserialization of interface types is not supported. Type 'Microsoft.AspNetCore.Http.IFormFile'. Path: $ .imageFile | LineNumber: 0 | BytePositionInLine: 6939781.
---> System.NotSupportedException: Deserialization of interface types is not supported. Type 'Microsoft.AspNetCore.Http.IFormFile'.
Anything I try to fix, it causes another error, I'm really at a loss.
Regards
>.append ('groupImage', values.imageFile)
Firstly, please make sure the key of your formdata object can match your model class property's name.
formData.append('imageName', values.imageName);
//...
//it should be imageFile, not groupImage
formData.append('imageFile', values.imageFile);
Besides, please apply the [FromForm] attribute to action parameter, like below.
public void Post([FromForm]Group group)
{
//...
Test Result
Usually a 415 means you aren't setting the right Content-Type header. Does the API you are trying to upload to mention acceptable types or encodings it expects?

Self reference type in GraphQL [duplicate]

Hi I am trying to learn GraphQL language. I have below snippet of code.
// Welcome to Launchpad!
// Log in to edit and save pads, run queries in GraphiQL on the right.
// Click "Download" above to get a zip with a standalone Node.js server.
// See docs and examples at https://github.com/apollographql/awesome-launchpad
// graphql-tools combines a schema string with resolvers.
import { makeExecutableSchema } from 'graphql-tools';
// Construct a schema, using GraphQL schema language
const typeDefs = `
type User {
name: String!
age: Int!
}
type Query {
me: User
}
`;
const user = { name: 'Williams', age: 26};
// Provide resolver functions for your schema fields
const resolvers = {
Query: {
me: (root, args, context) => {
return user;
},
},
};
// Required: Export the GraphQL.js schema object as "schema"
export const schema = makeExecutableSchema({
typeDefs,
resolvers,
});
// Optional: Export a function to get context from the request. It accepts two
// parameters - headers (lowercased http headers) and secrets (secrets defined
// in secrets section). It must return an object (or a promise resolving to it).
export function context(headers, secrets) {
return {
headers,
secrets,
};
};
// Optional: Export a root value to be passed during execution
// export const rootValue = {};
// Optional: Export a root function, that returns root to be passed
// during execution, accepting headers and secrets. It can return a
// promise. rootFunction takes precedence over rootValue.
// export function rootFunction(headers, secrets) {
// return {
// headers,
// secrets,
// };
// };
Request:
{
me
}
Response:
{
"errors": [
{
"message": "Field \"me\" of type \"User\" must have a selection of subfields. Did you mean \"me { ... }\"?",
"locations": [
{
"line": 4,
"column": 3
}
]
}
]
}
Does anyone know what I am doing wrong ? How to fix it ?
From the docs:
A GraphQL object type has a name and fields, but at some point those
fields have to resolve to some concrete data. That's where the scalar
types come in: they represent the leaves of the query.
GraphQL requires that you construct your queries in a way that only returns concrete data. Each field has to ultimately resolve to one or more scalars (or enums). That means you cannot just request a field that resolves to a type without also indicating which fields of that type you want to get back.
That's what the error message you received is telling you -- you requested a User type, but you didn't tell GraphQL at least one field to get back from that type.
To fix it, just change your request to include name like this:
{
me {
name
}
}
... or age. Or both. You cannot, however, request a specific type and expect GraphQL to provide all the fields for it -- you will always have to provide a selection (one or more) of fields for that type.

Sending json object as json array to an API

I have an API that accepts data format as [ { "record_id": "TestID3" } ]. I am trying to send record_id field using the form below in my angular project:
html:
<input id="record_id" type="text" class="form-control" [(ngModel)]="member.record_id" name="record_id" #record_id="ngModel" placeholder="Enter Record ID">
component.ts:
export class MembersAddComponent implements OnInit {
member: Array<Object> = [];
constructor(private service: DataService ) { }
ngOnInit() {
}
submit() {
this.service.importRecord(this.member).subscribe(member => {
this.member = member;
}, error => {
console.log(error);
});
}
}
And my service.ts:
importRecord(data): Observable<any> {
const formData = new FormData();
formData.append('token', this.token);
formData.append('content', this.content);
formData.append('format', this.format);
formData.append('returnFormat', this.returnFormat);
formData.append('type', this.type);
formData.append('overwriteBehavior', this.overwriteBehavior);
formData.append('forceAutoNumber', this.forceAutoNumber);
formData.append('data', data);
formData.append('returnContent', this.returnContent);
return this.http.post(this.baseUrl, formData).map(res => res.json())
.catch(this.handleError);
}
The error that I get is below:
{"error":"The data being imported is not formatted correctly. The JSON must be in an array, as in [{ ... }]."}
I also tried member:any = {}, member:Object = {}; but I got the same error. I am thinking that I am unable to format my member object as requested format. But I couldn't make it as desired format.
[ { "record_id": "TestID3" } ]
That is an array, containing a single element, which is an object.
member: Array<Object> = [];
that defines an array with no element at all.
[(ngModel)]="member.record_id"
That will try to read and write the property record_id of member, which is an array. It will not magically add an element to the array and set its property.
So what you need is an object that will be populated by the form. And then you need to put that object into an array before to send the array to the API.
Start by defining an interface to describe your object:
interface Member {
record_id: string;
}
Then use one as the model for your form:
member: Member = {
record_id: '';
};
...
[(ngModel)]="member.record_id"
Then put that member into an array before sending it:
submit() {
const data: Array<Member> = [this.member];
this.service.importRecord(data)...
It's difficult to tell if this is due to an incorrectly formatted response from the POST or the body of the POST.
Things you can do:
Check the network tab in Chrome to verify that the request is being sent, it's content is valid JSON (use an online validator)
Check your API backend to see if the data you're sending is being saved, if so the error is with the format of the JSON in your response.
Verify in Chrome that the response data in the network request is valid JSON.
If all of these are true, you may need to consider using headers such as {requestType: 'json'} as detailed in the Angular docs here: Request/Response Headers
If these are not true, then you will need to change the model of the object you are sending to reflect the object which is expected.

With GraphQL + Apollo Client, how to return a totalCount after mutating?

I have the following:
const typeDefs = `
type Request {
id: ID!
email: String!
totalCount: Int
}
type Mutation {
createRequest(email: String!): Request!
}
`;
export default typeDefs;
Right now totalCount is returning null. Using GraphQL, what is the right way to return the TotalCount as the mutation's response. Should totalCount be included somehow in the Request model?
You've defined totalCount as a property of each Request object but totalCount represents the count of all Request objects.
The common practice to allow additional data in mutation response is to have it return a wrapper. For example:
type Mutation {
createRequest(email: String!): CreateRequestResponse!
}
type CreateRequestResponse {
request: Request!
totalCount: Int!
}
The CreateRequestResponse is a wrapper object that can include any arbitrary attributes that the clients might need in the response. totalCount here is just an example; you can add any attribute there.
With that, the definition of Request type would be:
type Request {
id: ID!
email: String!
}
which is ideal because it only contains attributes of a specific Request.

Resources