Here I discuss the implementation of GraphQL in my Project data structure.
In my project, I am using flat files(text files) fixed-width format for DB management. I want to integrate API developments with that. flat files queried from CPP program. In this case, I struggle to choose GraphQL API for CPP Node Addon Native modules (OR) Nodejs NPM module GraphQL.
case 1: Is there a way to use flat file configuration for the NPM GraphQL package?
case 2: Is there a way to write Node Native moduels using node-addon-api? (For CPP developers used GraphQL parser from the opensource project in github named as cppgraphqlgen)
If I am choosing the second case, I am facing the following issues.
I am trying to write as cppgraphqlgen service as node addon native modules. I refer to more topics about that. In my project, some modules were already written in CPP Node addon Native modules using Napi.h. In this cppgraphqlgen project written in different API like nan.h. cppgraphiql uses Nan. I struggle to write these services as node addons for my project.
In my project Make file likes below:
CFLAGS = -Os -O3 -fPIC -Ofast -std=gnu++17
CC = gcc
CXX = g++
LDFLAGS := \
-pthread \
-rdynamic
DEFS := \
'-DUSING_UV_SHARED=1' \
'-DUSING_V8_SHARED=1' \
'-DV8_DEPRECATION_WARNINGS=1' \
'-DV8_DEPRECATION_WARNINGS' \
'-DV8_IMMINENT_DEPRECATION_WARNINGS' \
'-D_LARGEFILE_SOURCE' \
'-D_FILE_OFFSET_BITS=64' \
'-DOPENSSL_NO_PINSHARED' \
'-DOPENSSL_THREADS' \
'-D__STDC_FORMAT_MACROS' \
'-DNAPI_DISABLE_CPP_EXCEPTIONS' \
'-DBUILDING_NODE_EXTENSION'
# Flags passed to all source files.
GYP_CFLAGS := \
-frtti \
-fexceptions \
-pthread \
-Wall \
-Wextra \
-Wno-unused-parameter \
-fno-omit-frame-pointer
# Flags passed to only C files.
CFLAGS_C :=
# Flags passed to only C++ files.
CFLAGS_CC := \
-std=gnu++1y \
-fexceptions
INC_NAPI := -I/usr/include/node-addon-api
INC_NODE := -I/usr/include/node
CGI_LIB = -lcgicc
LIBS := ../cppgraphqlgen/src
NOTH_A = nothing.a
OBJ = nothing.o ./hello/HelloClient.o
ENODE = ${NOTH_A} ./hello/HelloClient.node
# GREET_DEMO = ./greet-demo
# CLASS_DEMO = ./class-demo
DEMO := ./today
HELLO := ./hello
target: ${OBJ} ${ENODE}
clean:
rm -rf *.o *.node *.a
rm -rf ${DEMO}/*.o ${DEMO}/*.node
rm -rf ${HELLO}/*.o ${HELLO}/*.node
# ./hello/hello: ./hello/hello.cpp
# ${CXX} ${CFLAGS} $< -o $@
./hello/hello:
${CXX} ${CFLAGS} ./hello/hello.cpp -shared -Wl,-soname=hello.node -Wl,--start-group -L${LIBS}/separategraphql.a -L${LIBS}/graphqljson.a -L${LIBS}/separateschema.a -L${LIBS}/graphqlintrospection.a -L${LIBS}/graphqlservice.a -L${LIBS}/graphqlresponse.a -L${LIBS}/graphqlpeg.a -lpthread ${NOTH_A} -Wl,--end-group -o $@
./hello/HelloClient.o: ./hello/HelloClient.cpp
${CXX} ${CFLAGS} '-DNODE_GYP_MODULE_NAME=HelloClient' ${DEFS} ${GYP_CFLAGS} ${CFLAGS_CC} ${INC_NAPI} ${INC_NODE} $< -o $@
./hello/HelloClient.node: ./hello/HelloClient.o
${CXX} ${CFLAGS} -shared -Wl,-soname=HelloClient.node -Wl,--start-group ./hello/HelloClient.o -L${LIBS}/separategraphql.a -L${LIBS}/graphqljson.a -L${LIBS}/separateschema.a -L${LIBS}/graphqlintrospection.a -L${LIBS}/graphqlservice.a -L${LIBS}/graphqlresponse.a -L${LIBS}/graphqlpeg.a -lpthread ${NOTH_A} -Wl,--end-group -o $@
nothing.a: nothing.o
ar crs nothing.a $<
nothing.o: nothing.c
${CC} ${LDFLAGS} ${INC_NODE} ${DEFS} -c $< -o $@
In cppgraphqlgen has two services named schemegen and clientgen. the mentioned two services are built successfully. This utility uses CMake (requires GNU 10.3.0). But in my project has the utility GNU Make. My make utility build command doesn't compile sample programs of cppgraphqlgen projects with node-addon-api (Napi.h). I want a simple getting-started program for cppgraphqlgen project.
For Example:
using schemagen service, the Auto-Generated files are HelloSchema.cpp and HelloSchema.h
using clientgen service, the Auto-Generated files are HelloClient.cpp and HelloClient.h
I changed HelloClient.cpp as node addon native
HelloClient.cpp
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// WARNING! Do not edit this file manually, your changes will be overwritten.
#include <napi.h>
#include "HelloClient.h"
#include <algorithm>
#include <array>
#include <stdexcept>
#include <sstream>
#include <string_view>
using namespace std::literals;
namespace graphql::client {
using namespace query::Query;
namespace query::Query {
const std::string& GetRequestText() noexcept
{
static const auto s_request = R"gql(
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
query {
hello
}
)gql"s;
return s_request;
}
const peg::ast& GetRequestObject() noexcept
{
static const auto s_request = []() noexcept {
auto ast = peg::parseString(GetRequestText());
// This has already been validated against the schema by clientgen.
ast.validated = true;
return ast;
}();
return s_request;
}
Response parseResponse(response::Value&& response)
{
Response result;
if (response.type() == response::Type::Map)
{
auto members = response.release<response::MapType>();
for (auto& member:members)
{
if (member.first == R"js(hello)js"sv)
{
result.hello = ModifiedResponse<response::StringType>::parse<TypeModifier::Nullable>(std::move(member.second));
continue;
}
}
}
return result;
}
} // namespace query::Query
} // namespace graphql::client
Napi::Object InitAll(Napi::Env env, Napi::Object exports) {
// auto expected = "Test String";
// auto actual = graphql::response::Value(expected);
// std::string res = graphql::client::query::Query::parseResponse(actual);
exports.Set("test", "test"); // <--- Here How to call and get the result "Hello World!"
return exports;
}
NODE_API_MODULE(NODE_GYP_MODULE_NAME, InitAll);
Input schema
type Query {
hello: String
}
Input Query:
{hello}
Output like:
{"data":{"hello":"Hello World!"}}
Another try like samples program in that project folder named today (sample.cpp using TodayMock. I try to write HelloMock)
HelloMock.h
#pragma once
#ifndef HELLOMOCK_H
#define HELLOMOCK_H
#include "HelloSchema.h"
#include <atomic>
#include <stack>
namespace graphql::hello
{
class Query
{
public:
using greetMsg = std::function<std::optional<response::StringType>>();
explicit Query(greetMsg &&getHello);
virtual service::FieldResult<std::optional<response::StringType>> getHello() final;
};
}
#endif // HELLOMOCK_H
HelloMock.cpp
#include "HelloMock.h"
#include <algorithm>
#include <iostream>
namespace graphql::hello
{
Query::Query(greetMsg &&getHello)
{
}
service::FieldResult<std::optional<response::StringType>> Query::getHello()
{
return "Hello World";
}
} // namespace graphql::hello
hello.cpp
#include "HelloMock.h"
#include "graphqlservice/JSONResponse.h"
#include <cstdio>
#include <iostream>
#include <iterator>
#include <stdexcept>
using namespace graphql;
int main(int argc, char **argv)
{
/* From HelloMock*/
response::StringType helloKey;
std::string fakeHelloKey("hello");
helloKey.resize(fakeHelloKey.size());
std::copy(fakeHelloKey.cbegin(), fakeHelloKey.cend(), helloKey.begin());
std::cout << "Created the service..." << std::endl;
auto query = std::make_shared<hello::Query>(
[&fakeHelloKey]() -> std::optional<response::StringType>
{
std::cout << "Called getHelloMsg..." << std::endl;
return std::optional<response::StringType>();
}
);
auto service = std::make_shared<hello::Operations>(query);
std::cout << "Created the service..." << std::endl;
try
{
peg::ast query;
if (argc > 1)
{
query = peg::parseFile(argv[1]);
}
else
{
std::istream_iterator<char> start{std::cin >> std::noskipws}, end{};
std::string input{start, end};
query = peg::parseString(std::move(input));
}
if (!query.root)
{
std::cerr << "Unknown error!" << std::endl;
std::cerr << std::endl;
return 1;
}
std::cout << "Executing query..." << std::endl;
std::cout << response::toJSON(service
->resolve(nullptr,
query,
((argc > 2) ? argv[2] : ""),
response::Value(response::Type::Map))
.get())
<< std::endl;
}
catch (const std::runtime_error &ex)
{
std::cerr << ex.what() << std::endl;
return 1;
}
return 0;
}
NodeJS program:
var express = require('express');
var {
graphqlHTTP
} = require('express-graphql');
var {
buildSchema
} = require('graphql');
var schema = buildSchema(`
type Query {
hello: String
}
`);
var root = {
hello: () => 'Hello world!'
};
var app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true,
}));
app.listen(4000, () => console.log('Now browse to localhost:4000/graphql'));
If there is a way to use flat files in GraphQL API services. Please Let me know. I want to eagerly write a Newer implementation with GraphQL API for my project. And how to use and implement node addon in the second clientgen Service? What is the use of clientgen? Please help me.