在这里,我将讨论 GraphQL 在我的 Project 数据结构中的实现。
在我的项目中,我使用平面文件(文本文件)固定宽度格式进行数据库管理。我想将 API 开发与它集成。从 CPP 程序查询的平面文件。在这种情况下,我很难为 CPP Node Addon Native modules (OR) Nodejs NPM module GraphQL 选择 GraphQL API。
案例 1:有没有办法为NPM GraphQL 包使用平面文件配置?
案例 2:有没有办法使用 node-addon-api 编写 Node Native 模块?(对于 CPP 开发人员使用来自 github 中名为cppgraphqlgen的开源项目的 GraphQL 解析器)
如果我选择第二种情况,我将面临以下问题。
我正在尝试将 cppgraphqlgen 服务编写为节点插件本机模块。我提到了更多关于那个的话题。在我的项目中,一些模块已经使用Napi.h在 CPP Node 插件 Native 模块中编写。在这个用不同 API 编写的 cppgraphqlgen 项目中,比如nan.h。cppgraphiql使用 Nan。我很难将这些服务编写为我的项目的节点插件。
在我的项目中制作文件如下:
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 $@
在 cppgraphqlgen 中有两个名为 schemegen 和 clientgen 的服务。上述两项服务均已成功构建。此实用程序使用 CMake(需要 GNU 10.3.0)。但在我的项目中有实用程序 GNU Make。我的 make 实用程序构建命令不会使用 node-addon-api (Napi.h) 编译 cppgraphqlgen 项目的示例程序。我想要一个用于 cppgraphqlgen 项目的简单入门程序。
例如:
使用 schemagen 服务,自动生成的文件是 HelloSchema.cpp 和 HelloSchema.h
使用 clientgen 服务,自动生成的文件是 HelloClient.cpp 和 HelloClient.h
我将 HelloClient.cpp 更改为节点插件本机
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);
输入架构
type Query {
hello: String
}
输入查询:
{hello}
输出如:
{"data":{"hello":"Hello World!"}}
另一个尝试在名为 today 的项目文件夹中的示例程序(使用 TodayMock 的 sample.cpp。我尝试编写 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
你好.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程序:
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'));
如果有办法在 GraphQL API 服务中使用平面文件。请告诉我。我想为我的项目急切地使用 GraphQL API 编写一个较新的实现。以及如何在第二个clientgen服务中使用和实现node addon?客户端有什么用?请帮我。