Quran API (#205)

* Add basic version of a Quran API

* remove examples json swp

* fix search translation

* add examples json
This commit is contained in:
Asim Aslam
2021-09-14 18:45:22 +01:00
committed by GitHub
parent b50d585e02
commit f0542b1a6a
14 changed files with 2530 additions and 0 deletions

2
quran/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
quran

3
quran/Dockerfile Normal file
View File

@@ -0,0 +1,3 @@
FROM alpine
ADD quran /quran
ENTRYPOINT [ "/quran" ]

28
quran/Makefile Normal file
View File

@@ -0,0 +1,28 @@
GOPATH:=$(shell go env GOPATH)
.PHONY: init
init:
go get -u github.com/golang/protobuf/proto
go get -u github.com/golang/protobuf/protoc-gen-go
go get github.com/micro/micro/v3/cmd/protoc-gen-micro
go get github.com/micro/micro/v3/cmd/protoc-gen-openapi
.PHONY: api
api:
protoc --openapi_out=. --proto_path=. proto/quran.proto
.PHONY: proto
proto:
protoc --proto_path=. --micro_out=. --go_out=:. proto/quran.proto
.PHONY: build
build:
go build -o quran *.go
.PHONY: test
test:
go test -v ./... -cover
.PHONY: docker
docker:
docker build . -t quran:latest

6
quran/README.md Normal file
View File

@@ -0,0 +1,6 @@
The Holy Quran
# Quran Service
The Holy Quran powered by [Quran.com](https://quran.api-docs.io)

206
quran/domain/domain.go Normal file
View File

@@ -0,0 +1,206 @@
package domain
import (
"strings"
pb "github.com/micro/services/quran/proto"
)
var (
// the default tafsir author
tafsir = map[int32]string{
169: "Tafsir Ibn Kathir",
}
)
type Chapter struct {
Id int32 `json:"id"`
RevelationPlace string `json:"revelation_place"`
RevelationOrder int32 `json:"revelation_order"`
BismillahPrefix bool `json:"bismillah_pre"`
NameSimple string `json:"name_simple"`
NameComplex string `json:"name_complex"`
NameArabic string `json:"name_arabic"`
VersesCount int32 `json:"verses_count"`
Pages []int32 `json:"pages"`
TranslatedName *TranslatedName `json:"translated_name"`
}
type TranslatedName struct {
LanguageName string `json:"language_name"`
Name string `json:"name"`
}
type TranslationText struct {
Id int32 `json:"id"`
ResourceId int32 `json:"resource_id"`
Text string `json:"text"`
ResourceName string `json:"resource_name"`
}
type Translation struct {
Text string `json:"text"`
LanguageName string `json:"language_name"`
}
type Transliteration struct {
Text string `json:"text"`
LanguageName string `json:"language_name"`
}
type Tafsir struct {
Id int32 `json:"id"`
ResourceId int32 `json:"resource_id"`
Text string `json:"text"`
}
type ChapterInfo struct {
Id int32 `json:"id"`
ChapterId int32 `json:"chapter_id"`
LanguageName string `json:"language_name"`
ShortText string `json:"short_text"`
Source string `json:"source"`
Text string `json:"text"`
}
type Pagination struct {
PerPage int32 `json:"per_page"`
CurrentPage int32 `json:"current_page"`
NextPage int32 `json:"next_page"`
TotalPages int32 `json:"total_pages"`
TotalRecords int32 `json:"total_records"`
}
type Verse struct {
Id int32 `json:"id"`
VerseNumber int32 `json:"verse_number"`
VerseKey string `json:"verse_key"`
JuzNumber int32 `json:"juz_number"`
HizbNumber int32 `json:"hizb_number"`
RubNumber int32 `json:"rub_number"`
PageNumber int32 `json:"page_number"`
Translations []*TranslationText `json:"translations"`
Tafsirs []*Tafsir `json:"tafsirs"`
Words []*Word `json:"words"`
TextImlaei string `json:"text_imlaei"`
}
type Word struct {
Id int32 `json:"id"`
Position int32 `json:"position"`
AudioUrl string `json:"audio_url"`
CharTypeName string `json:"char_type_name"`
CodeV1 string `json:"code_v1"`
PageNumber int32 `json:"page_number"`
LineNumber int32 `json:"line_number"`
Text string `json:"text_imlaei"`
Code string `json:"code_v2"`
Translation *Translation `json:"translation"`
Transliteration *Translation `json:"transliteration"`
}
type Result struct {
VerseId int32 `json:"verse_id"`
VerseKey string `json:"verse_key"`
Text string `json:"text"`
Translations []*SearchTranslation `json:"translations"`
}
type SearchResults struct {
Query string `json:"query"`
TotalResults int32 `json:"total_results"`
CurrentPage int32 `json:"current_page"`
TotalPages int32 `json:"total_pages"`
Results []*Result `json:"results"`
}
type SearchTranslation struct {
ResourceId int32 `json:"resource_id"`
Text string `json:"text"`
Name string `json:"name"`
}
type VersesByChapter struct {
Pagination *Pagination `json:"pagination"`
Verses []*Verse `json:"verses"`
}
func VerseToProto(verse *Verse) *pb.Verse {
var transliteration []string
var translation []string
var words []*pb.Word
for _, word := range verse.Words {
words = append(words, &pb.Word{
Id: word.Id,
Position: word.Position,
CharType: word.CharTypeName,
Page: word.PageNumber,
Line: word.LineNumber,
Text: word.Text,
Code: word.Code,
Translation: word.Translation.Text,
Transliteration: word.Transliteration.Text,
})
// skip the end
if word.CharTypeName == "end" {
continue
}
translation = append(translation, word.Translation.Text)
transliteration = append(transliteration, word.Transliteration.Text)
}
var translations []*pb.Translation
for _, tr := range verse.Translations {
translations = append(translations, &pb.Translation{
Id: tr.Id,
Source: tr.ResourceName,
Text: tr.Text,
})
}
var interpretations []*pb.Interpretation
for _, tf := range verse.Tafsirs {
interpretations = append(interpretations, &pb.Interpretation{
Id: tf.Id,
Source: tafsir[tf.ResourceId],
Text: tf.Text,
})
}
return &pb.Verse{
Id: verse.Id,
Key: verse.VerseKey,
Number: verse.VerseNumber,
Page: verse.PageNumber,
Text: verse.TextImlaei,
TranslatedText: strings.Join(translation, " "),
Transliteration: strings.Join(transliteration, " "),
Words: words,
Translations: translations,
Interpretations: interpretations,
}
}
func ResultToProto(r *Result) *pb.Result {
var translations []*pb.Translation
for _, tr := range r.Translations {
translations = append(translations, &pb.Translation{
Id: tr.ResourceId,
Source: tr.Name,
Text: tr.Text,
})
}
return &pb.Result{
VerseKey: r.VerseKey,
VerseId: r.VerseId,
Text: r.Text,
Translations: translations,
}
}

142
quran/examples.json Normal file
View File

@@ -0,0 +1,142 @@
{
"chapters": [{
"title": "List Chapters",
"run_check": false,
"request": {
"language": "en"
},
"response": {
"chapters": [{
"id": 1,
"verses": 7,
"name": "Al-Fatihah",
"arabic_name": "الفاتحة",
"complex_name": "Al-Fātiĥah",
"translated_name": "The Opener",
"prefix_bismillah": false,
"revelation_place": "makkah",
"revelation_order": 5,
"pages": [
1,
1
]
},
{
"id": 2,
"verses": 286,
"name": "Al-Baqarah",
"arabic_name": "البقرة",
"complex_name": "Al-Baqarah",
"translated_name": "The Cow",
"prefix_bismillah": true,
"revelation_place": "madinah",
"revelation_order": 87,
"pages": [
2,
49
]
},
{
"id": 3,
"verses": 200,
"name": "Ali 'Imran",
"arabic_name": "آل عمران",
"complex_name": "Āli `Imrān",
"translated_name": "Family of Imran",
"prefix_bismillah": true,
"revelation_place": "madinah",
"revelation_order": 89,
"pages": [
50,
76
]
}]
}
}],
"summary": [{
"title": "Get chapter summary",
"run_check": false,
"request": {
"chapter": 1
},
"response": {
"chapter": 1,
"summary": "This Surah is named Al-Fatihah because of its subject matter. Fatihah is that which opens a subject or a book or any other thing. In other words, Al-Fatihah is a sort of preface.",
"source": "Sayyid Abul Ala Maududi - Tafhim al-Qur'an - The Meaning of the Quran",
"text": "\u003ch2\u003eName\u003c/h2\u003e\u003cp\u003eThis Surah is named Al-Fatihah because of its subject matter. Fatihah is that which opens a subject or a book or any other thing. In other words, Al-Fatihah is a sort of preface.\u003c/p\u003e\u003ch2\u003ePeriod of Revelation\u003c/h2\u003e\u003cp\u003eSurah Al-Fatihah is one of the very earliest Revelations to the Holy Prophet. As a matter of fact, we learn from authentic traditions that it was the first complete Surah that was revealed to Muhammad (Allah's peace be upon him). Before this, only a few miscellaneous verses were revealed which form parts of Alaq, Muzzammil, Muddaththir, etc.\u003c/p\u003e\u003ch2\u003eTheme\u003c/h2\u003e\u003cp\u003eThis Surah is in fact a prayer that Allah has taught to all those who want to make a study of His book. It has been placed at the very beginning of the Quran to teach this lesson to the reader: if you sincerely want to benefit from the Quran, you should offer this prayer to the Lord of the Universe.\u003c/p\u003e\u003cp\u003eThis preface is meant to create a strong desire in the heart of the reader to seek guidance from the Lord of the Universe Who alone can grant it. Thus Al-Fatihah indirectly teaches that the best thing for a man is to pray for guidance to the straight path, to study the Quran with the mental attitude of a seeker searching for the truth, and to recognize the fact that the Lord of the Universe is the source of all knowledge. He should, therefore, begin the study of the Quran with a prayer to Him for guidance.\u003c/p\u003e\u003cp\u003eFrom this theme, it becomes clear that the real relation between Al-Fatihah and the Quran is not that of an introduction to a book but that of a prayer and its answer. Al-Fatihah is the prayer from the servant and the Quran is the answer from the Master to the servant's prayer. The servant prays to Allah to show him guidance and the Master places the whole of the Quran before him in answer to his prayer, as if to say, \"This is the Guidance you begged from Me.\"\u003c/p\u003e"
}
}],
"verses": [{
"title": "Get verses of a chapter",
"run_check": false,
"request": {
"chapter": 1
},
"response": {
"chapter": 1,
"page": 1,
"total_pages": 1,
"verses": [{
"id": 1,
"number": 1,
"key": "1:1",
"page": 1,
"text": "بِسْمِ اللَّهِ الرَّحْمَٰنِ الرَّحِيمِ",
"transliteration": "bis'mi l-lahi l-raḥmāni l-raḥīmi",
"translated_text": "In (the) name (of) Allah the Most Gracious the Most Merciful",
"translations": [],
"interpretations": [],
"words": []
},
{
"id": 2,
"number": 2,
"key": "1:2",
"page": 1,
"text": "الْحَمْدُ لِلَّهِ رَبِّ الْعَالَمِينَ",
"transliteration": "al-ḥamdu lillahi rabbi l-ʿālamīna",
"translated_text": "All praises and thanks (be) to Allah the Lord of the universe",
"translations": [],
"interpretations": [],
"words": []
},
{
"id": 3,
"number": 3,
"key": "1:3",
"page": 1,
"text": "الرَّحْمَٰنِ الرَّحِيمِ",
"transliteration": "al-raḥmāni l-raḥīmi",
"translated_text": "The Most Gracious the Most Merciful",
"translations": [],
"interpretations": [],
"words": []
}]
}
}],
"search": [{
"title": "Search the Quran",
"run_check": false,
"request": {
"query": "messenger"
},
"response": {
"query": "messenger",
"total_results": 5756,
"page": 1,
"total_pages": 288,
"results": [{
"verse_id": 4211,
"verse_key": "40:78",
"text": "وَلَقَدْ أَرْسَلْنَا رُسُلًا مِّن قَبْلِكَ مِنْهُم مَّن قَصَصْنَا عَلَيْكَ وَمِنْهُم مَّن لَّمْ نَقْصُصْ عَلَيْكَ ۗ وَمَا كَانَ لِرَسُولٍ أَن يَأْتِىَ بِـَٔايَةٍ إِلَّا بِإِذْنِ ٱللَّهِ ۚ فَإِذَا جَآءَ أَمْرُ ٱللَّهِ قُضِىَ بِٱلْحَقِّ وَخَسِرَ هُنَالِكَ ٱلْمُبْطِلُونَ",
"translations": [
{
"id": 171,
"source": "Abridged Explanation of the Quran",
"text": "O \u003cem\u003eMessenger\u003c/em\u003e! I have sent many \u003cem\u003emessengers\u003c/em\u003e before you to their people, but they rejected them and caused them harm. The \u003cem\u003emessengers\u003c/em\u003e were patient upon the rejection and harm they faced. From among these \u003cem\u003emessengers\u003c/em\u003e are those whom I have related their stories to you, and those whose stories I have not related. It is not correct for a \u003cem\u003emessenger\u003c/em\u003e to bring a sign to his people from his Lord, except if He (may He be glorified) wishes for him to bring it. So, for the disbelievers to demand signs is wrong. When the decree of Allah for victory or judgement in favour of the \u003cem\u003emessengers\u003c/em\u003e against their nations happens, the judgement will be made fairly. The disbelievers will then be destroyed and the \u003cem\u003emessengers\u003c/em\u003e will be saved. At that point when the judgement is made between the servants, the people of falsehood will lose out by having put themselves in a position of doom by committing disbelief."
}
]
}]
}
}]
}

3
quran/generate.go Normal file
View File

@@ -0,0 +1,3 @@
package main
//go:generate make proto

197
quran/handler/quran.go Normal file
View File

@@ -0,0 +1,197 @@
package handler
import (
"context"
"fmt"
"net/url"
"github.com/micro/micro/v3/service/errors"
"github.com/micro/micro/v3/service/logger"
"github.com/micro/services/pkg/api"
"github.com/micro/services/quran/domain"
pb "github.com/micro/services/quran/proto"
)
const (
// the default api url
apiUrl = "https://api.quran.com/api/v4/"
// TODO: allow multiple translations
// the default translation id
translationId = "131,20"
// TODO: allow multiple interpretations
// the default tafsir id
tafsirId = "169"
// TODO: make configurable
arabicText = "text_imlaei"
)
type Quran struct{}
// Chapters returns a list of the chapters of the Quran
func (q *Quran) Chapters(ctx context.Context, req *pb.ChaptersRequest, rsp *pb.ChaptersResponse) error {
lang := "en"
if len(req.Language) > 0 {
lang = req.Language
}
var resp map[string][]*domain.Chapter
if err := api.Get(apiUrl+"chapters?language="+lang, &resp); err != nil {
logger.Errorf("Failed to retrieve chapters: %v", err)
return errors.InternalServerError("quran.chapters", "Failed to retrieve chapters")
}
for _, c := range resp["chapters"] {
rsp.Chapters = append(rsp.Chapters, &pb.Chapter{
Id: c.Id,
RevelationPlace: c.RevelationPlace,
RevelationOrder: c.RevelationOrder,
PrefixBismillah: c.BismillahPrefix,
Name: c.NameSimple,
ComplexName: c.NameComplex,
ArabicName: c.NameArabic,
TranslatedName: c.TranslatedName.Name,
Verses: c.VersesCount,
Pages: c.Pages,
})
}
return nil
}
// Retrieve the summary for a given chapter
func (q *Quran) Summary(ctx context.Context, req *pb.SummaryRequest, rsp *pb.SummaryResponse) error {
lang := "en"
if len(req.Language) > 0 {
lang = req.Language
}
if req.Chapter <= 0 {
return errors.BadRequest("quran.chapter-summary", "require chapter id")
}
var resp map[string]*domain.ChapterInfo
uri := fmt.Sprintf(apiUrl+"chapters/%d/info?language=%s", req.Chapter, lang)
if err := api.Get(uri, &resp); err != nil {
logger.Errorf("Failed to retrieve chapter info: %v", err)
return errors.InternalServerError("quran.chapter-summary", "Failed to retrieve chapter summary")
}
info := resp["chapter_info"]
rsp.Chapter = info.ChapterId
rsp.Summary = info.ShortText
rsp.Source = info.Source
rsp.Text = info.Text
return nil
}
// Return the verses by chapter
func (q *Quran) Verses(ctx context.Context, req *pb.VersesRequest, rsp *pb.VersesResponse) error {
lang := "en"
if len(req.Language) > 0 {
lang = req.Language
}
if req.Chapter <= 0 {
return errors.BadRequest("quran.verses", "require chapter id")
}
// TODO: enable configuring translations
// comma separated list of resource ids
// https://quran.api-docs.io/v4/resources/translations
translations := translationId
// TODO: enable configuring tafirs
// https://api.quran.com/api/v4/resources/tafsirs
tafsirs := tafsirId
uri := fmt.Sprintf(apiUrl+"verses/by_chapter/%d?language=%s", req.Chapter, lang)
// additional fields we require
// arabic text in imlaei script
uri += "&fields=" + arabicText
uri += "&words=true"
uri += "&word_fields=code_v2,text_imlaei"
if len(translations) > 0 && req.Translate {
uri += "&translations=" + translations
uri += "&translation_fields=resource_name"
}
if len(tafsirs) > 0 && req.Interpret {
uri += "&tafsirs=" + tafsirs
}
if req.Page > 0 {
uri += fmt.Sprintf("&page=%d", req.Page)
}
if req.Limit > 0 {
uri += fmt.Sprintf("&per_page=%d", req.Limit)
}
var resp *domain.VersesByChapter
if err := api.Get(uri, &resp); err != nil {
logger.Errorf("Failed to retrieve verses: %v", err)
return errors.InternalServerError("quran.verses", "Failed to retrieve verses")
}
rsp.Chapter = req.Chapter
rsp.Page = resp.Pagination.CurrentPage
rsp.TotalPages = resp.Pagination.TotalPages
for _, verse := range resp.Verses {
v := domain.VerseToProto(verse)
// strip words if not asked for
if req.Words != true {
v.Words = nil
}
rsp.Verses = append(rsp.Verses, v)
}
return nil
}
// Return the search results for a given query
func (q *Quran) Search(ctx context.Context, req *pb.SearchRequest, rsp *pb.SearchResponse) error {
if len(req.Query) == 0 {
return errors.BadRequest("quran.search", "missing search query")
}
lang := "en"
if len(req.Language) > 0 {
lang = req.Language
}
if req.Limit <= 0 {
req.Limit = 20
}
qq := url.Values{}
qq.Set("q", req.Query)
qq.Set("size", fmt.Sprintf("%d", req.Limit))
qq.Set("page", fmt.Sprintf("%d", req.Page))
qq.Set("language", lang)
uri := fmt.Sprintf(apiUrl+"search?%s", qq.Encode())
var resp map[string]*domain.SearchResults
if err := api.Get(uri, &resp); err != nil {
logger.Errorf("Failed to retrieve search results: %v", err)
return errors.InternalServerError("quran.search", "Failed to retrieve search results")
}
rsp.Query = req.Query
rsp.Page = resp["search"].CurrentPage
rsp.TotalPages = resp["search"].TotalPages
rsp.TotalResults = resp["search"].TotalResults
for _, result := range resp["search"].Results {
r := domain.ResultToProto(result)
rsp.Results = append(rsp.Results, r)
}
return nil
}

25
quran/main.go Normal file
View File

@@ -0,0 +1,25 @@
package main
import (
"github.com/micro/services/quran/handler"
pb "github.com/micro/services/quran/proto"
"github.com/micro/micro/v3/service"
"github.com/micro/micro/v3/service/logger"
)
func main() {
// Create service
srv := service.New(
service.Name("quran"),
service.Version("latest"),
)
// Register handler
pb.RegisterQuranHandler(srv.Server(), new(handler.Quran))
// Run service
if err := srv.Run(); err != nil {
logger.Fatal(err)
}
}

1
quran/micro.mu Normal file
View File

@@ -0,0 +1 @@
service quran

1577
quran/proto/quran.pb.go Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,144 @@
// Code generated by protoc-gen-micro. DO NOT EDIT.
// source: proto/quran.proto
package quran
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
import (
context "context"
api "github.com/micro/micro/v3/service/api"
client "github.com/micro/micro/v3/service/client"
server "github.com/micro/micro/v3/service/server"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
// Reference imports to suppress errors if they are not otherwise used.
var _ api.Endpoint
var _ context.Context
var _ client.Option
var _ server.Option
// Api Endpoints for Quran service
func NewQuranEndpoints() []*api.Endpoint {
return []*api.Endpoint{}
}
// Client API for Quran service
type QuranService interface {
Chapters(ctx context.Context, in *ChaptersRequest, opts ...client.CallOption) (*ChaptersResponse, error)
Summary(ctx context.Context, in *SummaryRequest, opts ...client.CallOption) (*SummaryResponse, error)
Verses(ctx context.Context, in *VersesRequest, opts ...client.CallOption) (*VersesResponse, error)
Search(ctx context.Context, in *SearchRequest, opts ...client.CallOption) (*SearchResponse, error)
}
type quranService struct {
c client.Client
name string
}
func NewQuranService(name string, c client.Client) QuranService {
return &quranService{
c: c,
name: name,
}
}
func (c *quranService) Chapters(ctx context.Context, in *ChaptersRequest, opts ...client.CallOption) (*ChaptersResponse, error) {
req := c.c.NewRequest(c.name, "Quran.Chapters", in)
out := new(ChaptersResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *quranService) Summary(ctx context.Context, in *SummaryRequest, opts ...client.CallOption) (*SummaryResponse, error) {
req := c.c.NewRequest(c.name, "Quran.Summary", in)
out := new(SummaryResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *quranService) Verses(ctx context.Context, in *VersesRequest, opts ...client.CallOption) (*VersesResponse, error) {
req := c.c.NewRequest(c.name, "Quran.Verses", in)
out := new(VersesResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *quranService) Search(ctx context.Context, in *SearchRequest, opts ...client.CallOption) (*SearchResponse, error) {
req := c.c.NewRequest(c.name, "Quran.Search", in)
out := new(SearchResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Quran service
type QuranHandler interface {
Chapters(context.Context, *ChaptersRequest, *ChaptersResponse) error
Summary(context.Context, *SummaryRequest, *SummaryResponse) error
Verses(context.Context, *VersesRequest, *VersesResponse) error
Search(context.Context, *SearchRequest, *SearchResponse) error
}
func RegisterQuranHandler(s server.Server, hdlr QuranHandler, opts ...server.HandlerOption) error {
type quran interface {
Chapters(ctx context.Context, in *ChaptersRequest, out *ChaptersResponse) error
Summary(ctx context.Context, in *SummaryRequest, out *SummaryResponse) error
Verses(ctx context.Context, in *VersesRequest, out *VersesResponse) error
Search(ctx context.Context, in *SearchRequest, out *SearchResponse) error
}
type Quran struct {
quran
}
h := &quranHandler{hdlr}
return s.Handle(s.NewHandler(&Quran{h}, opts...))
}
type quranHandler struct {
QuranHandler
}
func (h *quranHandler) Chapters(ctx context.Context, in *ChaptersRequest, out *ChaptersResponse) error {
return h.QuranHandler.Chapters(ctx, in, out)
}
func (h *quranHandler) Summary(ctx context.Context, in *SummaryRequest, out *SummaryResponse) error {
return h.QuranHandler.Summary(ctx, in, out)
}
func (h *quranHandler) Verses(ctx context.Context, in *VersesRequest, out *VersesResponse) error {
return h.QuranHandler.Verses(ctx, in, out)
}
func (h *quranHandler) Search(ctx context.Context, in *SearchRequest, out *SearchResponse) error {
return h.QuranHandler.Search(ctx, in, out)
}

191
quran/proto/quran.proto Normal file
View File

@@ -0,0 +1,191 @@
syntax = "proto3";
package quran;
option go_package = "./proto;quran";
service Quran {
rpc Chapters(ChaptersRequest) returns (ChaptersResponse) {}
rpc Summary(SummaryRequest) returns (SummaryResponse) {}
rpc Verses(VersesRequest) returns (VersesResponse) {}
rpc Search(SearchRequest) returns (SearchResponse) {}
}
message Chapter {
// The id of the chapter as a number e.g 1
int32 id = 1;
// The number of verses in the chapter
int32 verses = 2;
// The simple name of the chapter
string name = 3;
// The arabic name of the chapter
string arabic_name = 4;
// The complex name of the chapter
string complex_name = 5;
// The translated name
string translated_name = 6;
// Should the chapter start with bismillah
bool prefix_bismillah = 7;
// The place of revelation
string revelation_place = 8;
// The order in which it was revealed
int32 revelation_order = 9;
// The pages from and to e.g 1, 1
repeated int32 pages = 10;
}
message Verse {
// The unique id of the verse in the whole book
int32 id = 1;
// The verse number in this chapter
int32 number = 2;
// The key of this verse (chapter:verse) e.g 1:1
string key = 3;
// The page of the Quran this verse is on
int32 page = 4;
// The arabic text for this verse
string text = 5;
// The phonetic transliteration from arabic
string transliteration = 6;
// The basic translation of the verse
string translated_text = 7;
// The alternative translations for the verse
repeated Translation translations = 8;
// The interpretations of the verse
repeated Interpretation interpretations = 9;
// The individual words within the verse (Ayah)
repeated Word words = 10;
}
message Interpretation {
// The unique id of the interpretation
int32 id = 1;
// The source of the interpretation
string source = 2;
// The translated text
string text = 3;
}
message Translation {
// The unique id of the translation
int32 id = 1;
// The source of the translation
string source = 2;
// The translated text
string text = 3;
}
message Word {
// The id of the word within the verse
int32 id = 1;
// The position of the word
int32 position = 2;
// The character type e.g word, end
string char_type = 3;
// The page number
int32 page = 4;
// The line number
int32 line = 5;
// The arabic text for this word
string text = 6;
// The QCF v2 font code
string code = 7;
// The translated text
string translation = 8;
// The transliteration text
string transliteration = 9;
}
message Result {
// The unique verse id across the Quran
int32 verse_id = 1;
// The verse key e.g 1:1
string verse_key = 2;
// The associated arabic text
string text = 3;
// The related translations to the text
repeated Translation translations = 4;
}
// List the Chapters (surahs) of the Quran
message ChaptersRequest {
// Specify the language e.g en
string language = 1;
}
message ChaptersResponse {
repeated Chapter chapters = 1;
}
// Get a summary for a given chapter (surah)
message SummaryRequest {
// The chapter id e.g 1
int32 chapter = 1;
// Specify the language e.g en
string language = 2;
}
message SummaryResponse {
// The chapter id
int32 chapter = 1;
// The short summary for the chapter
string summary = 2;
// The source of the summary
string source = 3;
// The full description for the chapter
string text = 4;
}
// Lookup the verses (ayahs) for a chapter
message VersesRequest {
// The chapter id to retrieve
int32 chapter = 1;
// The language of translation
string language = 2;
// Return the individual words with the verses
bool words = 3;
// Return the interpretation (tafsir)
bool interpret = 4;
// Return alternate translations
bool translate = 5;
// The page number to request
int32 page = 6;
// The verses per page
int32 limit = 7;
}
message VersesResponse {
// The chapter requested
int32 chapter = 1;
// The page requested
int32 page = 2;
// The total pages
int32 total_pages = 3;
// The verses on the page
repeated Verse verses = 4;
}
// Search the Quran for any form of query or questions
message SearchRequest {
// The query to ask
string query = 1;
// The language for translation
string language = 2;
// The number of results to return
int32 limit = 3;
// The pagination number
int32 page = 4;
}
message SearchResponse {
// The question asked
string query = 1;
// The total results returned
int32 total_results = 2;
// The current page
int32 page = 3;
// The total pages
int32 total_pages = 4;
// The results for the query
repeated Result results = 5;
}

5
quran/publicapi.json Normal file
View File

@@ -0,0 +1,5 @@
{
"name": "quran",
"icon": "📖",
"category": "religion"
}