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
...