fetch
type Course struct {
Name string
Teacher string
Students []Student
Capacity int
}
type Student struct {
FirstName string
LastName string
ID string
}
c := Course {
Name: "IE",
Teacher: "Bahador Bakhshi",
Students: []Student{
{ FirstName: "Parham", LastName: "Alvani", ID: "9231058" },
},
Capacity: 30,
}
{
"name": "IE",
"teacher": "Bahador Bakhshi",
"students": [
{ "first_name": "Parham", "last_name": "Alvani", "id": "9231058" }
],
"capacity": 30
}
A4 # map(4)
64 # text(4)
6E616D65 # "name"
62 # text(2)
4945 # "IE"
67 # text(7)
74656163686572 # "teacher"
6F # text(15)
42616861646F722042616B68736869 # "Bahador Bakhshi"
68 # text(8)
73747564656E7473 # "students"
81 # array(1)
A3 # map(3)
6A # text(10)
66697273745F6E616D65 # "first_name"
66 # text(6)
50617268616D # "Parham"
69 # text(9)
6C6173745F6E616D65 # "last_name"
66 # text(6)
416C76616E69 # "Alvani"
62 # text(2)
6964 # "id"
67 # text(7)
39323331303538 # "9231058"
68 # text(8)
6361706163697479 # "capacity"
18 1E # unsigned(30)
IE
Bahador Bakhshi
30
1
Parham
Alvani
9231058
{
"name": "IE",
"teacher": "Bahador Bakhshi",
"students": [
{ "first_name": "Parham", "last_name": "Alvani", "id": "9231058" }
],
"capacity": 30
}
"This is a string"
42
3.1415926
{ "key1": "value1", "key2": "value2" }
[ "first", "second", "third" ]
true
false
null
{}
type
keyword is used
for that.
{ "type": "string" }
$schema
keyword is used to declare
that something is JSON Schema.
{ "$schema": "http://json-schema.org/draft-07/schema#" }
{ "$schema": "http://json-schema.org/draft/2019-09/schema#" }
$id
property as a unique identifier for
each schema.
{ "$id": "http://yourdomain.com/schemas/myschema.json" }
title
,
description
,
default
,
examples
that
aren't strictly used for validation,
but are used to describe parts of a schema.title
and
description
keywords must be strings.default
keyword specifies a default
value for an item.
{ "type": "string" }
minLength
and
maxLength
keywords.pattern
keyword is used to restrict
a string to a particular regular expression.format
keyword allows for basic
semantic validation on certain kinds of string values that are
commonly used.
{ "type": "integer" }
{ "type": "number" }
multipleOf
minimum
and
maximum
keywords
{ "type": "object" }
properties
keyword.properties
is an object,
where each key is the name of a property and each value is a JSON
schema used to validate that property.
{
"type": "object",
"properties": {
"number": { "type": "number" },
"street_name": { "type": "string" },
"street_type": { "type": "string",
"enum": ["Street", "Avenue", "Boulevard"]
}
}
}
additionalProperties
keyword is used
to control the handling of extra stuffproperties
keyword.additionalProperties
is an object,
that object is a schema that will be used to validate any additional
properties not listed in properties.
{
"type": "object",
"properties": {
"number": { "type": "number" },
"street_name": { "type": "string" },
"street_type": { "enum": ["Street", "Avenue", "Boulevard"] }
},
"additionalProperties": { "type": "string" }
}
{
"type": "object",
"properties": {
"number": { "type": "number" },
"street_name": { "type": "string" },
"street_type": { "enum": ["Street", "Avenue", "Boulevard"] }
},
"additionalProperties": false
}
required
keyword takes an array of
zero or more strings.
{
"type": "object",
"properties": {
"name": { "type": "string" },
"email": { "type": "string" },
"address": { "type": "string" },
"telephone": { "type": "string" }
},
"required": ["name", "email"]
}
{ "type": "array" }
items
keyword to a single schema that
will be used to validate all of the items in the array.
{
"type": "array",
"items": {
"type": "number"
}
}
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Product",
"type": "object",
"properties": {
"id": {
"type": "number",
"description": "Product identifier"
},
"name": { "type": "string" },
"price": { "type": "number", "minimum": 0 },
"tags": {
"type": "array",
"items": { "type": "string" }
},
"stock": {
"type": "object",
"properties": {
"warehouse": { "type": "number" },
"retail": { "type": "number" }
}
}
}
}
{
"id": 1,
"name": "Foo",
"price": 123,
"tags": [
"Bar",
"Eek"
],
"stock": {
"warehouse": 300,
"retail": 20
}
}
The JSON object
, has two very useful
methods to deal with JSON-formatted contentJSON.parse()
takes a JSON string and
transforms it into a JavaScript objectJSON.stringify()
takes a JavaScript object
and transforms it into a JSON string
let myObj = { a: '1', b: 2, c: '3' };
let myObjStr = JSON.stringify(myObj);
console.log(myObjStr);
console.log(JSON.parse(myObjStr));
{
"type": "object",
"properties": {
"messages": {
"type": "array",
"items": {
"type": "object",
"properties": {
"from": {
"type": "string"
},
"to": {
"type": "string"
},
"body": {
"type": "string"
}
}
}
}
}
}
function parseJSON() {
output = "";
input = document.getElementById("json-in-2").value;
jsonData = JSON.parse(input);
for (i = 0; i < jsonData.messages.length; i++) {
msg = jsonData.messages[i];
output += `
${msg.from} sent the following message to ${msg.to}<br />${msg.body}<hr />`;
}
document.getElementById("json-out-2").innerHTML = output;
}
document.getElementById("json-btn-2").onclick = parseJSON;
Languages supported by Apache Thrift :
Go | C | Python |
JavaScript | C++ | TypeScript |
OCaml | Objective-C | ActionScript |
Ruby | Haxe | Cappuccino |
AS3 | Node.js | Cocoa |
D | Php | Elixir |
Dart | Smalltalk | Scala |
Haskell | C# | Swift |
Lua | Erlang | Delphi |
Perl | Java | Rust |
/**
* Thrift files can reference other Thrift files to include common struct
* and service definitions. These are found using the current path, or by
* searching relative to any paths specified with the -I compiler flag.
*
* Included objects are accessed using the name of the .thrift file as a
* prefix. i.e. shared.SharedObject
*/
include "shared.thrift"
/**
* You can define enums, which are just 32 bit integers. Values are optional
* and start at 1 if not supplied, C style again.
*/
enum Operation {
ADD = 1,
SUBTRACT = 2,
MULTIPLY = 3,
DIVIDE = 4
}
/**
* Structs are the basic complex data structures. They are comprised of fields
* which each have an integer identifier, a type, a symbolic name, and an
* optional default value.
*
* Fields can be declared "optional", which ensures they will not be included
* in the serialized output if they aren't set. Note that this requires some
* manual management in some languages.
*/
struct Work {
1: i32 num1 = 0,
2: i32 num2,
3: Operation op,
4: optional string comment,
}
/**
* Structs can also be exceptions, if they are nasty.
*/
exception InvalidOperation {
1: i32 whatOp,
2: string why
}
/**
* Ahh, now onto the cool part, defining a service. Services just need a name
* and can optionally inherit from another service using the extends keyword.
*/
service Calculator extends shared.SharedService {
/**
* A method definition looks like C code. It has a return type, arguments,
* and optionally a list of exceptions that it may throw. Note that argument
* lists and exception lists are specified using the exact same syntax as
* field lists in struct or exception definitions.
*/
void ping(),
i32 add(1:i32 num1, 2:i32 num2),
i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch),
/**
* This method has a oneway modifier. That means the client only makes
* a request and does not listen for any response at all. Oneway methods
* must be void.
*/
oneway void zip()
}
if __name__ == "__main__":
# Make socket
transport = TSocket.TSocket('localhost', 9090)
# Buffering is critical. Raw sockets are very slow
transport = TTransport.TBufferedTransport(transport)
# Wrap in a protocol
protocol = TBinaryProtocol.TBinaryProtocol(transport)
# Create a client to use the protocol encoder
client = Calculator.Client(protocol)
# Connect!
transport.open()
client.ping()
print('ping()')
sum_ = client.add(1, 1)
public static void main(String [] args) {
try {
handler = new CalculatorHandler();
processor = new Calculator.Processor(handler);
Runnable simple = new Runnable() {
public void run() {
simple(processor);
}
};
new Thread(simple).start();
new Thread(secure).start();
} catch (Exception x) {
x.printStackTrace();
}
}
public static void simple(Calculator.Processor processor) {
try {
TServerTransport serverTransport = new TServerSocket(9090);
TServer server = new TSimpleServer(new Args(serverTransport).processor(processor));
// Use this for a multithreaded server
// TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).processor(processor));
System.out.println("Starting the simple server...");
server.serve();
} catch (Exception e) {
e.printStackTrace();
}
}
public class CalculatorHandler implements Calculator.Iface {
private HashMap<Integer,SharedStruct> log;
public CalculatorHandler() {
log = new HashMap<Integer, SharedStruct>();
}
public void ping() {
System.out.println("ping()");
}
public int add(int n1, int n2) {
System.out.println("add(" + n1 + "," + n2 + ")");
return n1 + n2;
}
public int calculate(int logid, Work work) throws InvalidOperation {
System.out.println("calculate(" + logid + ", {" + work.op + "," + work.num1 + "," + work.num2 + "})");
int val = 0;
switch (work.op) {
case ADD:
val = work.num1 + work.num2;
break;
case SUBTRACT:
val = work.num1 - work.num2;
break;
case MULTIPLY:
val = work.num1 * work.num2;
break;
case DIVIDE:
if (work.num2 == 0) {
InvalidOperation io = new InvalidOperation();
io.whatOp = work.op.getValue();
io.why = "Cannot divide by 0";
throw io;
}
val = work.num1 / work.num2;
break;
default:
InvalidOperation io = new InvalidOperation();
io.whatOp = work.op.getValue();
io.why = "Unknown operation";
throw io;
}
SharedStruct entry = new SharedStruct();
entry.key = logid;
entry.value = Integer.toString(val);
log.put(logid, entry);
return val;
}
public SharedStruct getStruct(int key) {
System.out.println("getStruct(" + key + ")");
return log.get(key);
}
public void zip() {
System.out.println("zip()");
}
}