Anagram Server是一个基于Node.js的应用程序,它揭示了基于REST的API,用于针对单词字典进行与Anagram相关的搜索。它的主要特征是为给定单词找到已知的Anagram。
此外,可以通过基数(集合中的单词数)或单词长度查询Anagram集(彼此为单位的单词组)。还可以查询给定的一组单词是否包含Anagram集。
可以添加,从API中添加,删除或完全清除字符的单词词典。当配置为仅内存的服务(即,更改不会在服务重新启动过程中持续存在)时,Anagram Server在启动时会预加载一组标准的英语单词(请参阅app.js
)。
最后,可以通过API查询有关加载字典的许多统计信息。
如有必要,安装node.js
安装NPM依赖项
npm install
npm start
默认情况下,该应用程序在端口3000上提供请求。要覆盖此内容,您可以在package.json
中更新start脚本。例如:
"start": "node src/app.js -p 8080"
您可能需要明确允许在有效端口上传入流量。例如,要在Linux上打开端口3000,直到下一个重新启动:
sudo iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 3000 -j ACCEPT
如有必要,请安装Docker
构建Docker图像
sudo docker build -t anagram-server .
sudo docker run -p 3000:3000 anagram-server
您可能更喜欢映射到替代主机端口(例如-p 8080:3000
)。
Anagram服务器带有Ruby Test脚本。
请注意,默认情况下,Anagram Server在启动上的dictionary.txt
中的单词预处理。
测试脚本在源软件包的test
子文件夹中,可以单独运行:
ruby anagram_test.rb
ruby anagram_test_2.rb
可以用cURL
或像Postman这样的工具手动测试Anagram服务器。例如(从应用程序主机的新终端窗口中的命令行):
curl -i "http://localhost:3000/anagrams/shout.json"
由于默认情况下,Anagram Server在启动上的dictionary.txt
中的单词预处理,因此您可能需要在测试之前使用以下命令清除字典:
curl -i -X DELETE "http://localhost:3000/words.json"
对于远程测试,请在anagram_client.rb
和本文档的示例命令中替换“ Localhost”。
还要在anagram_client.rb
和示例命令中更新端口号,如果使用默认值以外的端口运行Anagram服务器(3000)。
如果单词包含大写和小写英语字母字母或连字符的任何组合,则认为有效。有效的单词可能不会以连字符开始或结束。
尝试获取或删除无效的单词会导致400 Bad Request
。
尝试发布无效词的尝试导致204 No Content
。
专有名词被认为是具有所有小写字母的任何单词,除了第一个字母(必须是大写)和连字符后的第一个字母(可能是大写或小写)。
一些例子是:英语,Zulu,Jean-Christophe
专有名词被认为与其小写版本不同。例如,阿比盖尔(Abigail)和阿比盖尔(Abigail)是两个不同的单词(彼此的字眼)。
除非明确排除,否则始终包含专有名词(请参阅GET /anagrams/:word.json
的excludeProperNouns
parm)。
为了方便起见,Anagram服务器允许在某些情况下将适当名词与其小写版本匹配。例如,在查询Anagrams时:
$ curl -i "http://localhost:3000/anagrams/aaru.json?includeInput=true"
HTTP/1.1 200 OK
Content-Type: application/json
...
{ "anagrams": [
"Aaru",
"aura"]
}
Anagram服务器体系结构由4层组成(从最低级别到最高):
适配器是一类,可提供基本商店特定的查询,迭代和Anagram服务器使用的CRUD操作。具体而言,适配器提供了将键字符串与一组值相关联的语义,并从每个键的值集中添加并删除,查询按键设置的键以及迭代的键/设置对。
适配器从服务逻辑中抽象了基础存储机制的细节,以便将一种存储技术换成另一种存储技术。此抽象的值是提供一条简单的升级路径,因为出现了更有利的存储替代方案并允许灵活的可扩展性选项。
例如,该服务最初可以作为单个应用程序服务器推出,该应用程序使用适配器在同一服务器上包装MySQL实例。随着可扩展性,故障转移和性能需求的增加,我们可能会将适配器交换为包裹REDIS实例的适配器,该实例将持续存在并在多个服务器中复制其数据。数据如何存储,缓存和/或复制的细节与Anagram服务透明。
Anagram Server使用MemoryAdapter( adapters/MemoryAdapter.js
)运输,该服务器使用JavaScript的映射存储和查询数据。该适配器的应用程序有限,因为它没有提供跨服务器重新启动的持久性的好处,但它是测试和展示Anagram服务器功能的良好基础。
该项目定义了用于在文件adapters/adapter-template.js
中实现适配器的接口。该文件可以用作定义新适配器的样板。
适配器界面是基于承诺的,因为存储技术的API往往是异步的。从理论上讲,这增加了响应时间,因为承诺可以通过事件队列解决,但是在网络请求的范围内,这种效果可以忽略不计。
交易
适配器的add()
和delete()
方法要求基础存储以支持交易,因为它们的逻辑涉及查询数据,然后根据查询的结果在商店上操作。
克隆结果
MemoryAdapter get()
和each()
方法将映射值数组直接返回到AnagramService。这需要代表Anagramservice代码的勤奋,以避免这些方法提供的结果意外突变。
将结果克隆到记忆行动器之前将结果克隆在减轻未来的错误,确保接口一致性以及对消费者的惊讶最少的方面是明智的一步,但也涉及额外的(尽管可能可以忽略的)开销。
AnagramService是为Anagram服务器提供业务逻辑的类。它要求将适配器的实例传递给其构造函数。
AnagramService类维护字,Anagram计数和实现直接支持REST API的方法。
该课程生活在AnagramService.js
中。
server.js
导出一个单个函数startServer()
该函数可创建REST服务器(通过RESTIFY)并实例化AnagramService。
startServer()
需要一个适配器实例,并且可以选择接受一个端口号,从该端口号进行服务请求,并接受文本文件的可选路径,以从中填写字典。
server.js
的肉是解析单个HTTP请求的服务器响应功能集,调用相关的AnagramService方法,并使用适当的对象包装和HTTP响应代码发布响应。
app.js
是Anagram服务器的入口点。这是一个简单的文件,指定适配器运行服务的适配器和一个可选的数据预加载源。
这是将一个适配器换成另一个适配器时唯一需要更改的文件。
app.js
的当前版本在启动时使用MemoryAdapter和PRELOADS dictionary.txt
运行Anagramserver。
以下是一些进一步开发Anagram服务器的想法。
GET /anagrams/:word.json
返回一系列单词,这些单词是URL中传递的单词的字词。
如果传递的单词本身不是一个已知的单词(即,在字典中不是),则会返回一个空数组(即使可以从传递的单词中形成已知的Anagrams)。
为了方便起见,通过小写的单词将与其适当的名词形式相匹配。
例子:
$ curl -i "http://localhost:3000/anagrams/care.json"
HTTP/1.1 200 OK
Content-Type: application/json
...
{ "anagrams": [
"Acer",
"acre",
"crea",
"race"]
}
GET /anagrams/:word.json?limit=<integer>
返回json阵列,这些单词是在URL中传递的单词的字词,但限制了返回的结果数。
例子:
$ curl -i "http://localhost:3000/anagrams/care.json?limit=2"
HTTP/1.1 200 OK
Content-Type: application/json
...
{ "anagrams": [
"Acer",
"acre"]
}
GET /anagrams/:word.json?includeInput=true
返回一系列单词,这些单词是在URL中传递的单词的字词,包括输入单词本身。
输入单词通常不包含在Anagram结果中,因为通常不认为单词是本身的字词。
$ curl -i "http://localhost:3000/anagrams/care.json?includeInput=true"
HTTP/1.1 200 OK
Content-Type: application/json
...
{ "anagrams": [
"Acer",
"acre",
"care",
"crea",
"race"]
}
GET /anagrams/:word.json?excludeProperNouns=true
返回一系列单词,这些单词是在URL中传递的单词的词汇,省略了专有名词。
专有名词通常包含在Anagram结果中。
$ curl -i "http://localhost:3000/anagrams/care.json?limit=2&excludeProperNouns=true"
HTTP/1.1 200 OK
Content-Type: application/json
...
{ "anagrams": [
"acre",
"crea"]
}
GET /anagrams?cardinalityMin=<integer>&cardinalityMax=<integer>
返回具有最小和/或最大基数(集合中的Anagram数)的所有字符集。
可以省略心脏态度或核心态度。
示例:
$ curl -i "http://localhost:3000/anagrams?cardinalityMin=3&cardinalityMax=4"
HTTP/1.1 200 OK
Content-Type: application/json
...
{
"anagramsByCardinality": {
"cardinalityMin": 3,
"cardinalityMax": 4,
"anagrams": [
["Aaronic", "Nicarao", "ocarina"],
["abater", "artabe", "eartab", "trabea"],
["Abe", "bae", "Bea"],
...
]
}
}
# Return all words that have anagrams
$ curl -i "http://localhost:3000/anagrams?cardinalityMin=2"
HTTP/1.1 200 OK
Content-Type: application/json
...
{
"anagramsByCardinality": {
"cardinalityMin": 2,
"anagrams": [
["A", "a"],
["aal", "ala"],
["aam", "ama"],
...
]
}
}
GET /anagrams?lengthMin=<integer>&lengthMax=<integer>
返回具有最小和/或最大单词长度的所有字符集。
可以省略长度分钟或长度max。
例子:
$ curl -i "http://localhost:3000/anagrams?lengthMin=10&lengthMax=11"
HTTP/1.1 200 OK
Content-Type: application/json
...
{
"anagramsByLength": {
"lengthMin": 10,
"lengthMax": 11,
"anagrams": [
["ablastemic", "masticable"],
["aborticide", "bacterioid"],
["acalyptrate", "Calyptratae"],
...
]
}
}
GET /anagrams?maxCardinality=true
返回所有带有最大基数的字符集。
例子:
$ curl -i "http://localhost:3000/anagrams?maxCardinality=true"
HTTP/1.1 200 OK
Content-Type: application/json
...
{
"maxCardinalityAnagrams": {
"maxCardinality": 11,
"anagrams": [
["angor", "argon", "goran", "grano", "groan", "nagor", "Orang", "orang", "organ", "rogan", "Ronga"]
]
}
}
GET /anagrams?maxLength=true
返回所有带有最大单词长度的Anagram设置。
例子:
$ curl -i "http://localhost:3000/anagrams?maxLength=true"
HTTP/1.1 200 OK
Content-Type: application/json
...
{
"maxLengthAnagrams": {
"maxLength": 22,
"anagrams": [
["cholecystoduodenostomy", "duodenocholecystostomy"],
["hydropneumopericardium", "pneumohydropericardium"]
]
}
}
GET /anagrams?areAnagrams=<comma-delimited list of words>
确定一组单词是否是彼此的字符。
所有传递的单词都必须知道(即词典中),以使这是真实的。
例子:
$ curl -i "http://localhost:3000/anagrams?areAnagrams=acer,acre,race"
HTTP/1.1 200 OK
Content-Type: application/json
...
{
"anagramAffinity": {
"areAnagrams": true,
"words": ["acer", "acre", "race"]
}
}
GET /anagrams?count=true
返回Anagram仅计数。字典中的每组字词集都会在此计数中添加N-1 ,其中n是集合中的Anagram数量。
例子:
$ curl -i "http://localhost:3000/anagrams?count=true"
HTTP/1.1 200 OK
Content-Type: application/json
...
{ "counts": { "anagram": 20043 }}
GET /words?count=true
词典中的单词返回数量。
例子:
$ curl -i "http://localhost:3000/words?count=true"
HTTP/1.1 200 OK
Content-Type: application/json
...
{ "counts": { "word": 235886 }}
GET /words?stats=true
返回有关字典中这些单词的一些统计数据。
例子:
$ curl -i "http://localhost:3000/words?stats=true"
HTTP/1.1 200 OK
Content-Type: application/json
...
{
"stats": {
"wordCount": 235886,
"anagramCount": 20043,
"minWordLength": 1,
"maxWordLength": 24,
"medianWordLength": 4,
"averageWordLength": 9.569126612007494,
"minCardinality": 2,
"maxCardinality": 11,
"medianCardinality": 2,
"averageCardinality": 2.3111140184470464
}
}
POST /words.json
采用一系列单词,并将它们添加到字典中。
例子:
$ curl -i -X POST -d '{ "words": ["Canadas", "acandas", "Smurfs", "care"] }' "http://localhost:3000/words.json"
HTTP/1.1 201 Created
Content-Type: application/json
...
{
"counts": {
"word": 3,
"anagram": 1
},
"words": ["/anagrams/Canadas", "/anagrams/acandas", "/anagrams/Smurfs"]
}
DELETE /words/:word.json
从字典中删除一个单词。
如果传递的单词本身不是一个已知的单词(即词典中的单词),则返回404
。
例子:
$ curl -i -X DELETE "http://localhost:3000/words/care.json"
HTTP/1.1 204 No Content
...
DELETE /words/:word.json?includeAnagrams=true
从字典中删除一个单词及其所有字符。
如果传递的单词本身不是一个已知的单词(即,在字典中),则没有删除任何内容,并且返回404
。
例子:
$ curl -i -X DELETE "http://localhost:3000/words/acre.json?includeAnagrams=true"
HTTP/1.1 204 No Content
...
DELETE /words.json
清除字典中的所有内容。
例子:
$ curl -i -X DELETE "http://localhost:3000/words.json"
HTTP/1.1 204 No Content
...