JSON : Placeholder

JSON : Placeholder (https://jsonplaceholder.typicode.com/) 是一个用于测试的 REST API 网站。

以下使用 Task API/Rx.NET + Json.NET 调用该网站的 REST API,获取字符串以及 JSON 数据。

  • GET /posts/1
  • GET /posts
  • POST /posts
  • PUT /posts/1
  • DELETE /posts/1

所有 GET API 都返回JSON数据,格式(JSON-Schema)如下:

{
"type":"object",
"properties": {
"userId": {"type" : "integer"},
"id": {"type" : "integer"},
"title": {"type" : "string"},
"body": {"type" : "string"}
}
}

安装 C++ REST SDK

$ brew install cpprestsdk
$ brew install boost
$ brew install libressl

安装 "JSON for Modern C++"

$ brew tap nlohmann/json
$ brew install nlohmann_json

下载 RxCpp

$ git clone --recursive https://github.com/ReactiveX/RxCpp.git

创建工程

打开 Xcode,File / New / Project...

在向导的第1页选 macOS / Command Line Tool

在向导的第2页语言选 C++,Product Name 填上任意名称

在向导的第3页选择任意文件夹,点击 Create 创建工程。

配置工程

将 System Header Search Paths 设置为

/usr/local/Cellar/cpprestsdk/2.10.2/include

/usr/local/Cellar/boost/1.67.0_1/include

/usr/local/Cellar/libressl/2.7.4/include

/usr/local/Cellar/nlohmann_json/3.1.2/include

RxCpp安装文件夹/Rx/v2/src

将 Library Search Paths 设置为

/usr/local/Cellar/cpprestsdk/2.10.2/lib

/usr/local/Cellar/boost/1.67.0_1/lib

/usr/local/Cellar/libressl/2.7.4/lib

将 Other Linker Flags 设置为

-lcpprest -lboost_system -lboost_thread-mt -lboost_chrono-mt -lssl -lcrypto

cpprestsdk: Undefined symbols for architecture x86_64

Post

在工程中添加 post.hpp,内容如下

#ifndef Post_hpp
#define Post_hpp #include <iostream>
#include <nlohmann/json.hpp>
using nlohmann::json; struct Post {
int userId;
int id;
std::string title;
std::string body;
};
void to_json(json& j, const Post& p);
void from_json(const json& j, Post& p);
std::ostream& operator<<(std::ostream& out, const Post& p); #endif /* Post_hpp */

在工程中添加 post.cpp,内容如下

#include "Post.hpp"
#include <boost/algorithm/string/replace.hpp>
using namespace std; void to_json(json& j, const Post& p) {
j = json{{"userId", p.userId}, {"id", p.id}, {"title", p.title}, {"body", p.body}};
}
void from_json(const json& j, Post& p) {
p.userId = j.at("userId").get<int>();
p.id = j.at("id").get<int>();
p.title = j.at("title").get<string>();
p.body = boost::algorithm::replace_all_copy(j.at("body").get<string>(), "\n", "\\n");
}
std::ostream& operator<<(std::ostream& out, const Post& p) {
cout << "Post {userId = " << p.userId
<< ", id = " << p.id
<< ", title = \"" << p.title
<< "\", body = \"" << p.body
<< "\"}";
return out;
}

RestApi

在工程中添加 RestApi.hpp,内容如下

#ifndef RestApi_hpp
#define RestApi_hpp #include <cpprest/http_client.h>
#include <cpprest/filestream.h>
#include <cpprest/json.h> using namespace utility; // Common utilities like string conversions
//using namespace web; // Common features like URIs.
using namespace web::http; // Common HTTP functionality
using namespace web::http::client; // HTTP client features
using namespace concurrency::streams; // Asynchronous streams #include "rxcpp/rx.hpp"
namespace Rx {
using namespace rxcpp;
using namespace rxcpp::sources;
using namespace rxcpp::operators;
using namespace rxcpp::util;
}
using namespace Rx; #include <nlohmann/json.hpp>
using nlohmann::json; template<class T>
struct RestApi {
http_client client; RestApi(const uri &base_uri) : client(base_uri) {} observable<string_t> getString(const string_t &path_query_fragment) {
return observable<>::create<string_t>(
[&](subscriber<string_t> s){
client
.request(methods::GET, path_query_fragment)
.then([](http_response response) -> pplx::task<string_t> {
return response.extract_string();
})
.then([&](pplx::task<string_t> previousTask) {
try {
string_t const & v = previousTask.get();
s.on_next(v);
s.on_completed();
} catch (http_exception const & e) {
s.on_error(std::current_exception());
}
})
.wait();
});
} observable<T> getObject(const string_t &path_query_fragment) {
return observable<>::create<T>(
[&](subscriber<T> s){
client
.request(methods::GET, path_query_fragment)
.then([](http_response response) -> pplx::task<string_t> {
return response.extract_string();
})
.then([&](pplx::task<string_t> previousTask) {
try {
string_t const & v = previousTask.get();
json j = json::parse(v);
T t = j;
s.on_next(t);
s.on_completed();
} catch (http_exception const & e) {
s.on_error(std::current_exception());
}
})
.wait();
});
} observable<T> getArray(const string_t &path_query_fragment) {
return observable<>::create<T>(
[&](subscriber<T> s){
client
.request(methods::GET, path_query_fragment)
.then([](http_response response) -> pplx::task<string_t> {
return response.extract_string();
})
.then([&](pplx::task<string_t> previousTask) {
try {
string_t const & v = previousTask.get();
json j = json::parse(v);
std::vector<T> vec = j;
for(const auto& t : vec)
s.on_next(t);
s.on_completed();
} catch (http_exception const & e) {
s.on_error(std::current_exception());
}
})
.wait();
});
} observable<string_t> createObject(const string_t& url, const T& obj) {
return observable<>::create<string_t>(
[&](subscriber<string_t> s){
json j = obj;
client
.request(methods::POST, url, j.dump(), U("application/json"))
.then([](http_response response) -> pplx::task<string_t> {
return response.extract_string();
})
.then([&](pplx::task<string_t> previousTask) {
try {
string_t const & v = previousTask.get();
s.on_next(v);
s.on_completed();
} catch (http_exception const & e) {
s.on_error(std::current_exception());
}
})
.wait();
});
} observable<string_t> updateObject(const string_t& url, const T& obj) {
return observable<>::create<string_t>(
[&](subscriber<string_t> s){
json j = obj;
client
.request(methods::PUT, url, j.dump(), U("application/json"))
.then([](http_response response) -> pplx::task<string_t> {
return response.extract_string();
})
.then([&](pplx::task<string_t> previousTask) {
try {
string_t const & v = previousTask.get();
s.on_next(v);
s.on_completed();
} catch (http_exception const & e) {
s.on_error(std::current_exception());
}
})
.wait();
});
} observable<string_t> deleteObject(const string_t& url) {
return observable<>::create<string_t>(
[&](subscriber<string_t> s){
client
.request(methods::DEL, url)
.then([](http_response response) -> pplx::task<string_t> {
return response.extract_string();
})
.then([&](pplx::task<string_t> previousTask) {
try {
string_t const & v = previousTask.get();
s.on_next(v);
s.on_completed();
} catch (http_exception const & e) {
s.on_error(std::current_exception());
}
})
.wait();
});
}
}; #endif /* RestApi_hpp */

main

将 main.cpp 的内容改为

#include "Post.hpp"
#include "RestApi.hpp" using namespace std; int main(int argc, char* argv[])
{
RestApi<Post> api(U("https://jsonplaceholder.typicode.com/"));
api.getString(U("posts/1")).subscribe([](const string_t& v){cout << v << endl;});
api.getObject(U("posts/1")).subscribe([](const Post& v){cout << v << endl;});
api.getArray(U("posts")).take(2).subscribe([](const Post& v){cout << v << endl;});
Post o;
o.id = 0;
o.userId = 101;
o.title = U("test title");
o.body = U("test body");
api.createObject(U("posts"), o).subscribe([](string_t v){cout << v << endl;});
api.updateObject(U("posts/1"), o).subscribe([](string_t v){cout << v << endl;});
api.deleteObject(U("posts/1")).subscribe([](string_t v){cout << v << endl;}); return 0;
}

输出结果

{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}
Post {userId = 1, id = 1, title = "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", body = "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"}
Post {userId = 1, id = 1, title = "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", body = "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"}
Post {userId = 1, id = 2, title = "qui est esse", body = "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"}
{
"body": "test body",
"id": 101,
"title": "test title",
"userId": 101
}
{
"body": "test body",
"id": 1,
"title": "test title",
"userId": 101
}
{}

ReactiveX 学习笔记(24)使用 RxCpp + C++ REST SDK 调用 REST API的更多相关文章

  1. ReactiveX 学习笔记(14)使用 RxJava2 + Retrofit2 调用 REST API

    JSON : Placeholder JSON : Placeholder (https://jsonplaceholder.typicode.com/) 是一个用于测试的 REST API 网站. ...

  2. ReactiveX 学习笔记(18)使用 RxJS + Angular 调用 REST API

    JSON : Placeholder JSON : Placeholder (https://jsonplaceholder.typicode.com/) 是一个用于测试的 REST API 网站. ...

  3. ReactiveX 学习笔记(17)使用 RxSwift + Alamofire 调用 REST API

    JSON : Placeholder JSON : Placeholder (https://jsonplaceholder.typicode.com/) 是一个用于测试的 REST API 网站. ...

  4. ReactiveX 学习笔记(0)学习资源

    ReactiveX 学习笔记 ReactiveX 学习笔记(1) ReactiveX 学习笔记(2)创建数据流 ReactiveX 学习笔记(3)转换数据流 ReactiveX 学习笔记(4)过滤数据 ...

  5. guava 学习笔记(二) 瓜娃(guava)的API快速熟悉使用

    guava 学习笔记(二) 瓜娃(guava)的API快速熟悉使用 1,大纲 让我们来熟悉瓜娃,并体验下它的一些API,分成如下几个部分: Introduction Guava Collection ...

  6. 《深入Java虚拟机学习笔记》- 第19章 方法的调用与返回

    <深入Java虚拟机学习笔记>- 第19章 方法的调用与返回

  7. go微服务框架kratos学习笔记四(kratos warden-quickstart warden-direct方式client调用)

    目录 go微服务框架kratos学习笔记四(kratos warden-quickstart warden-direct方式client调用) warden direct demo-server gr ...

  8. [原创]java WEB学习笔记24:MVC案例完整实践(part 5)---删除操作的设计与实现

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  9. springmvc学习笔记--支持文件上传和阿里云OSS API简介

    前言: Web开发中图片上传的功能很常见, 本篇博客来讲述下springmvc如何实现图片上传的功能. 主要讲述依赖包引入, 配置项, 本地存储和云存储方案(阿里云的OSS服务). 铺垫: 文件上传是 ...

随机推荐

  1. 剑指Offer 39. 平衡二叉树 (二叉树)

    题目描述 输入一棵二叉树,判断该二叉树是否是平衡二叉树. 题目地址 https://www.nowcoder.com/practice/8b3b95850edb4115918ecebdf1b4d222 ...

  2. 11--Python入门--面向对象

    面向对象是Python的特点.面向对象主要通过类class的定义来实现.类class是用来描述具有相同属性和方法的对象的集合.类定义了该集合中的每个对象的共有属性和方法可以将类理解为一个模块,模块中包 ...

  3. 创建ApplicationContext与BeanFactory时的区别-Spring源码学习之容器的基本实现

    传送门 可以加载XML两种方法 使用 BeanFactory 加载 XML BeanFactory bf = new XmlBeanFactory(new ClassPathResource(&quo ...

  4. 常见模块(五) random模块

    random随机函数中的常用方法 1.random.random 返回一个介于左闭右开[0.0, 1.0)区间的浮点数 print(random.random()) 2.random.randrang ...

  5. psql的安装与数据库创建(ubuntu)

    来自阮一峰日志 http://www.ruanyifeng.com/blog/2013/12/getting_started_with_postgresql --------------------- ...

  6. fixed 相对于父容器定位

    当一个元素设置为 fixed 或 absolute,不设置 top, left 则会在原位置,而脱离文档流,别的元素可以存在于它之后. 而当使用 fixed 后还想相对于父容器进行定位,或者说在当前位 ...

  7. shell(2)图片重命名

    1:图片重命名 原来的图片名字格式: 改成的图片名字格式: #!/bin/bash #重命名 .png和.jpg #如果原文件的图片名称是从0开始,那么count=:从1开始,那么count= cou ...

  8. [转]golang的goroutine调度机制

    golang的goroutine调度机制 版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[-] 一直对goroutine的调度机制很好奇最近在看雨痕的golang源码分析基于go ...

  9. 彻底删除msde2008(请先在控制面板中卸载).bat

    彻底删除msde2008(请先在控制面板中卸载).bat @echo offset /P dv=请确认强制删除MSDE2008(请先在控制面板中卸载),Y=删除,N=退出:if not defined ...

  10. Linux操作redis 使用(VMwareWorkstation)

    项目一般都部署到linux上面,记得刚出来的时候,第一家公司 服务器是windows系统,以后公司的项目都放在了linux上面,所以掌握linux的一些基本操作是一个程序员必备的知识,本次记录如何使用 ...