Я видел кучу статей на эту тему (я думаю, вы тоже видели и сейчас думаете, что это очередной шлак) и всё сводилось к описанию роута на каждый api вызов, и в итоге мы получали кучку кода, с которым перейти на тот же jsonp требовалось пару дней (или недель). Также я часто встречал на тостере ответы, в которых писали, что нода сразу работает на всём (ajax, ws, jsonp, rpc-json). Правда ли это, я не знаю, но всё же мне пришло в голову исправить это. Я для своего проекта сделал апи сразу по трём протоколам, а именно: ajax, ws, jsonp (по сети ходит что то похожое на json-rpc).
Вот что мы имеем на сервере:
Теперь опишу, что здесь происходит. Метод api.AddMethod добавляет новый метод в пулл (метод принимает map и обязан вернуть map). Здесь тест. функции просто к полученным данным добавляют ещё данные и возвращают их. Потом api.RunServer запускает апи сервер на порту 8080. Данные по сети ходят в формате json. Формат ajax и ws одинаков.
А для jsonp он немного другой:
К всему этому добру я обращался из js. Со временем я сделал авто выбор протокола и чуть поже я сделал абстракцию над 3 протоколами, а в абстракцию пихал драйвер протокола который реализовал метод driver.send(data, call);. Я тогда разогнался с написанием плюшек к этому всему и слепил что то вроде микро фреймворка. (подобие MVC только вместо моделей мы делаем запросы к API прямо в контролере).
Потом я подумал что неплохо бы поделится своей работой с сообществом. Так я создал GoJs.
Он довольно мал, но имеет почти всё что нужно (а то, чего нет — сделаю; предлагайте в коментарии на почту v.grabko@box.ua, а в идеале в Pull Requests).
Итак, начнём погружение в этот мини фреймворк. Сначала необходимо создать скелет.
Теперь в корне проекта создаём три директории после создания клонируем в /js/GoJs фреймворк. Теперь запустим тестовый GoJsBackend сервер:
Во время запуска мы написали что хотим вызвать из контроллера start метод index. Пришло время его создать. В директории /app/controllers создадим start.js. Скелет контроллера (у всех он одинаков):
Что же сдесь происходит? Мы создаём обьект контроллера (фреймворк помистит его в обьект RegistryLoad.controllers).
Важно! После первой загрузки контроллер кешируется и потом повторно используется. Что бы его заново загрузить необходимо перезагрузить страницу!
Теперь, когда скелет создан, давайте сделаем запрос к серверу и полученые данные запихнём во вьюшку:
Теперь создаём в директории /app/views вьюшку. Все вьюшки имеют расширение .tpl, поэтому имя файла будет index.tpl со следующим содержанием:
А что, если нам необходимо выполнить несколько запросов к api? Вы наверное подумали, что необходимо сделать как то так:
Да, это работает. Но это, если честно, адский говнокод. Для этого создана абстракция, которая выполняет асинхронные запросы «синхронно». Вы наверное спросите: зачем городить велосипед, если можно использовать синхронные запросы? Всё очень просто: они подвесят браузер.
А что, если мы захотим данные из одного контроллера передать в другой? Об этом будет написано чуть ниже.
Роутер работает одновременно из html5.history и location.hash (вы абстрагированы). Все маршруты прописаны прямо во вьюшках. Их нет как таковых. Они автоматически парсятся после генерации ссылки. Например, мы захотим вызвать из контроллера errors метод NotFound:
Итак, что тут происходит:
А что, если мы захотели переменную передать в другой контролеер? Запросто:
А в вызванном контроллере пишем:
Но всё не так сладко, как кажется. К примеру, сейчас почему-то в Опере мини из контролера не вызывается вьюшка.
github.com/v-grabko/GoJs
github.com/v-grabko/GoJsBackend
Вот что мы имеем на сервере:
package main
import (
api "github.com/v-grabko/GoJsBackend"
"log"
)
func Testing(ps map[string]string) map[string]string {
ps["test"] = "Testing"
return ps
}
func main() {
api.AddMethod("TestMethod", func(ps map[string]string) map[string]string {
ps["test"] = "TestMethod"
return ps
})
api.AddMethod("Testing", Testing)
log.Fatal(api.RunServer(":8080"))
}
Теперь опишу, что здесь происходит. Метод api.AddMethod добавляет новый метод в пулл (метод принимает map и обязан вернуть map). Здесь тест. функции просто к полученным данным добавляют ещё данные и возвращают их. Потом api.RunServer запускает апи сервер на порту 8080. Данные по сети ходят в формате json. Формат ajax и ws одинаков.
type MyJsonNameB struct {
Data map[string]string `json:"data"`
Method string `json:"method"`
}
А для jsonp он немного другой:
type MyJsonName struct {
C string `json:"c"`
Data map[string]string `json:"data"`
Method string `json:"method"`
}
К всему этому добру я обращался из js. Со временем я сделал авто выбор протокола и чуть поже я сделал абстракцию над 3 протоколами, а в абстракцию пихал драйвер протокола который реализовал метод driver.send(data, call);. Я тогда разогнался с написанием плюшек к этому всему и слепил что то вроде микро фреймворка. (подобие MVC только вместо моделей мы делаем запросы к API прямо в контролере).
Потом я подумал что неплохо бы поделится своей работой с сообществом. Так я создал GoJs.
Он довольно мал, но имеет почти всё что нужно (а то, чего нет — сделаю; предлагайте в коментарии на почту v.grabko@box.ua, а в идеале в Pull Requests).
Итак, начнём погружение в этот мини фреймворк. Сначала необходимо создать скелет.
<html>
<head>
<!-- Подключим фреймворк-->
<script src="/js/GoJs/main.js"></script>
<!-- И запустим нашего зверя-->
<script>
main({
//конфигурация
controllers_dir: "/app/controllers",
views_dir: "/app/views",
gojs_dir: "/js/GoJs",
ApiServer: "localhost:8080"
},
//говорим что при старте выполнить из контроллера start метод index
"start@index",
//а в этой функции мы можем и обязаны кастомизировать что угодно.
function () {
});
</script>
</head>
<body>
<!--В этот див шаблонизатор будет грузить результат своей работы -->
<div id="page"></div>
</body>
</html>
Теперь в корне проекта создаём три директории после создания клонируем в /js/GoJs фреймворк. Теперь запустим тестовый GoJsBackend сервер:
/app/controllers
/app/views
/js/GoJs
Во время запуска мы написали что хотим вызвать из контроллера start метод index. Пришло время его создать. В директории /app/controllers создадим start.js. Скелет контроллера (у всех он одинаков):
start = {
index: function () {}
};
Что же сдесь происходит? Мы создаём обьект контроллера (фреймворк помистит его в обьект RegistryLoad.controllers).
Важно! После первой загрузки контроллер кешируется и потом повторно используется. Что бы его заново загрузить необходимо перезагрузить страницу!
Теперь, когда скелет создан, давайте сделаем запрос к серверу и полученые данные запихнём во вьюшку:
start = {
index: function () {
window.backend.Get({
method: "TestMethod",
data: {
event: "PageSkeleton",
data: "0"
}
}, function (t) {
View("index", t);
});
}
};
Теперь создаём в директории /app/views вьюшку. Все вьюшки имеют расширение .tpl, поэтому имя файла будет index.tpl со следующим содержанием:
{{var.event}}<br>
{{var.data}}<br>
{{var.test}}<br>
А что, если нам необходимо выполнить несколько запросов к api? Вы наверное подумали, что необходимо сделать как то так:
var modelData = {};
window.backend.Get({
method: "TestMethod",
data: {
event: "PageSkeleton",
data: "0"
}
}, function (t) {
modelData.TestMethod = t.test
window.backend.Get({
method: "Testing",
data: {
event: "PageSkeleton",
data: "0"
}
}, function (t) {
modelData.Testing = t.test
View("index", modelData);
});
});
{{var.TestMethod}}<br>
{{var.Testing}}<br>
Да, это работает. Но это, если честно, адский говнокод. Для этого создана абстракция, которая выполняет асинхронные запросы «синхронно». Вы наверное спросите: зачем городить велосипед, если можно использовать синхронные запросы? Всё очень просто: они подвесят браузер.
window.backend.GetSync([
{
method: "TestMethod",
data: {
event: "PageSkeleton",
data: "0"
}
},{
method: "Testing",
data: {
event: "PageSkeleton",
data: "0"
}
}
],function(ret){
View("index", {
TestMethod : ret.TestMethod.test,
Testing : ret.Testing.test
});
});
А что, если мы захотим данные из одного контроллера передать в другой? Об этом будет написано чуть ниже.
Роутинг
Роутер работает одновременно из html5.history и location.hash (вы абстрагированы). Все маршруты прописаны прямо во вьюшках. Их нет как таковых. Они автоматически парсятся после генерации ссылки. Например, мы захотим вызвать из контроллера errors метод NotFound:
{{href.RedHref|/errors/NotFound|Вызвать метод}}
Итак, что тут происходит:
RedHref ->всё что содержится здесь будет помещенно в атрибут class="" ссылки
/errors/NotFound ->здесь мы первым параметром передали имя контроллера, а вторим его метод.
Вызвать метод -> имя ссылки
А что, если мы захотели переменную передать в другой контролеер? Запросто:
{{href.RedHref|/errors/NotFound/vars/{{var.test}}|Вызвать метод}}
А в вызванном контроллере пишем:
errors = {
NotFound:function(){
alert(router.GetData("vars"));
},
};
Но всё не так сладко, как кажется. К примеру, сейчас почему-то в Опере мини из контролера не вызывается вьюшка.
github.com/v-grabko/GoJs
github.com/v-grabko/GoJsBackend