ferryawijayanto
ferryawijayanto

Reputation: 649

Has no property in common gRPC typescript

hi i'm new with typescript, i want to make a grpc server with typescript. But i have trouble with how my server.ts work. My GetAllNews service said

has no properties in common with type 'NewsList'

and i can't push into an array in my AddNews the message is

Argument of type '{ id: string; title?: string; body?: string; postImage?: string; }' is not assignable to parameter of type '{ id: string; title: string; body: string; postImage: string; }'. Property 'title' is optional in type '{ id: string; title?: string; body?: string; postImage?: string; }' but required in type '{ id: string; title: string; body: string; postImage: string; }'

and my EditNews service show an error

Type 'string | undefined' is not assignable to type 'string'

this is how i setup my server.ts . where do i do wrong?

import path from 'path'
import * as grpc from '@grpc/grpc-js'
import * as protoLoader from '@grpc/proto-loader'
import { v4 as uuidv4 } from 'uuid'
import { ProtoGrpcType } from './proto/news';
import { NewsServiceHandlers } from './proto/newsPackage/NewsService';

const PORT = 9999;
const PROTO_FILE = './proto/random.proto'

const packageDef = protoLoader.loadSync(path.resolve(__dirname, PROTO_FILE))
const grpcObj = (grpc.loadPackageDefinition(packageDef) as unknown) as ProtoGrpcType
const newsPackage = grpcObj.newsPackage
let newsLists = [
    { id: "1", title: "Note 1", body: "Content 1", postImage: "Post image 1" },
    { id: "2", title: "Note 2", body: "Content 2", postImage: "Post image 2" },
]

function main() {
    const server = getServer()
    server.bindAsync(`0.0.0.0:${PORT}`, grpc.ServerCredentials.createInsecure(),
    (err, port) => {
        if (err) {
            console.error(err)
            return
        }
        console.log('Your server is started on port', port)
        server.start()
    })
}

function getServer() {
    const server = new grpc.Server()
    server.addService(newsPackage.NewsService.service, {
        "GetAllNews": (_, callback) => {
            callback(null, newsLists)
        },
        "GetNews": (call, callback) => {
            const newsId = call.request.id
            const newsItem = newsLists.find(({ id }) => id !== newsId)
            callback(null, newsItem)
        },
        "AddNews": (call, callback) => {
            let news = { id: uuidv4(), ...call.request}
            newsLists.push(news)
            callback(null, news)
        }, 
        "EditNews": (call, callback) => {
            const newsId = call.request.id
            const newsItem = newsLists.find(({ id }) => newsId == id)
            newsItem.body = call.request.body
            newsItem.postImage = call.request.postImage
            newsItem.title = call.request.title
            callback(null, newsItem)
        },
        "DeleteNews": (call, callback) => {
            const newsId = call.request.id;
            newsLists = newsLists.filter(({ id }) => id !== newsId);
            callback(null, {});
        }
    } as NewsServiceHandlers)
    return server
}

main()

and this is my proto

syntax = "proto3";

package newsPackage;

message News {
    string id = 1;
    string title = 2;
    string body = 3;
    string postImage = 4;
}

service NewsService {
    rpc GetAllNews (Empty) returns (NewsList) {}
    rpc GetNews (NewsId) returns (News) {}
    rpc DeleteNews (NewsId) returns (Empty) {}
    rpc EditNews (News) returns (News) {}
    rpc AddNews (News) returns (News) {}
}

message NewsId {
    string id = 1;
}

message Empty {}

message NewsList {
   repeated News news = 1;
}

Upvotes: 0

Views: 836

Answers (1)

murgatroid99
murgatroid99

Reputation: 20277

The problem with your GetAllNews implementation is that your NewsList message definition is a message containing a repeated field named news of News messages, so the object that you pass should reflect that. In your code, you are passing a bare array of objects, but you should instead pass an object with a news field that points to that array.

The problem with your AddNews implementation is that objects that come from gRPC may have some fields omitted if those fields are set to the default value, but your newsLists variable has the inferred type { id: string; title: string; body: string; postImage: string; }[], which requires every field to be set in each item. You can solve this by setting the defaults option in protoLoader.loadSync or by explicitly declaring a type for newsLists that allows for unset fields.

The problem with EditNews seems to be a similar incompatibility as with AddNews, and the same solution should fix it.

Upvotes: 1

Related Questions